剑指Offer---面试题9---斐波那契数列

时间:2019-12-14
本文章向大家介绍剑指Offer---面试题9---斐波那契数列,主要包括剑指Offer---面试题9---斐波那契数列使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。



剑指Offer-面试题9---斐波那契数列

1、题目1:输出斐波那契数列

输入n,输出斐波那契数列位于第n位的值。

递归的方式效率会很低,因为会有大量重复的计算。所以这时按顺序推是个好办法。
我的解法:从前往后算,把计算过的值都存入数组中。

#include <iostream>
#include <vector>
using namespace std;

long long CalculateNums(vector<long long> nums,unsigned int n)
{
    nums[0] = 0;
    nums[1] = 1;
    //每次计算时先检测之前是否已经计算过
    if(n<nums.size()){
        return nums[n];
    }

    //接着从未计算过的位置开始计算
    for(int i=nums.size();i<=n;i++){
        nums.push_back(nums[i-1] + nums[i-2]);
    }
    return nums[n];
}

int main()
{
    int n;
    vector<long long> nums;
    //给初始的两个数预留空间
    nums.resize(2);
    while(cin>>n){
        if(n<0){
            cout<<"输入范围错误"<<endl;
        }
        else{
            cout<<CalculateNums(nums,n)<<endl;
        }
    }

    return 0;
}

2、题目2:青蛙跳台阶1

青蛙跳台阶1:青蛙一次可以挑1或2层台阶。求跳n层台阶有几种跳法。(n<=30)

跳台阶其实就和斐波那契数列基本一样。不再重复写了。

3、题目3:青蛙跳台阶2

青蛙跳台阶2:青蛙一次可以挑1、2、、n-1、n台阶。求跳n层台阶有几种跳法。(n<=30)

这道题的规律很好算:f(n) = 2^(n-1)

我的解法:我是用快速幂算的

long long CalculateWays(unsigned int n)
{
    if(n==0)
        return 0;
    if(n==1)
        return 1;
    n--;

    long long result = 1;
    long long base = 2;
    while(n != 0){
        if(n%2 !=0){
            result *= base;
        }
        base *= base;
        n /= 2;
    }

    return result;
}

大佬的解法:位运算,一行代码搞定!

long long CalculateWays(int n)
{
    if(n==0)
        return 0;
    return 1<<(n-1);
}

4、题目4:青蛙跳台阶3

青蛙跳台阶3:青蛙一次可以挑1或2层台阶。求跳n层台阶有几种跳法。(500>=n>=100)

这道题规定的范围明显超过了long long的范围,所以用到了大整数加运算。

我的解法:啰嗦的大整数+

#include <iostream>
#include <string>
using namespace std;

string CalculateWays(unsigned int n);

string BigNumAdd(string s1,string s2);

int main()
{

    int n;
    cin>>n;
    if(n<=0){
        cout<<"输入范围错误";
    }
    else{
        cout<<CalculateWays(n);
    }

    return 0;
}

string CalculateWays(unsigned int n)
{
    if(n==1)
        return "1";
    if(n==2)
        return "2";
    string lastlast = "1";
    string last = "2";
    string result = "0";
    for(int i=3;i<=n;i++){
        result = BigNumAdd(lastlast,last);
        lastlast = last;
        last = result;
    }
    return result;
}

string BigNumAdd(string s1,string s2)
{
    int len1 = s1.size()-1;
    int len2 = s2.size()-1;
    string result = "";
    int carry = 0;

    //先算两个数都有的位
    while(len1>=0 && len2>=0){
        int add = s1[len1] - 48 + s2[len2] - 48 + carry;
        carry = add/10;
        add%=10;

        char addChar = add+48;
        result = addChar + result;
        len1--;
        len2--;
    }

    //再算位数多的
    while(len1>=0){
        int add = s1[len1] - 48 + carry;
        carry = add/10;
        add%=10;

        char addChar = add+48;
        result = addChar + result;
        len1--;
    }
    while(len2>=0){
        int add = s2[len2] - 48 + carry;
        carry = add/10;
        add%=10;

        char addChar = add+48;
        result = addChar + result;
        len2--;
    }
    //最后是否进位
    if(carry > 0){
        char addChar = carry+48;
        result = addChar + result;
    }
    return result;
}

大佬的解法:优质的大整数+

#include <iostream>
#include <string>
#include <vector>
using namespace std;

string BigNumAddString(string s1,string s2)
{
    string& longStr = s1.size()>=s2.size()?s1:s2;
    string& shortStr = s1.size()<s2.size()?s1:s2;
    //给短的字符串前面填充0
    shortStr.insert(0,longStr.size()-shortStr.size(),'0');

    string result;
    //给result预留足够的空间
    result.resize(s1.size()+s2.size()+1);

    //取各自最后一个字符的下标(要从后向前加)
    int longIndex = longStr.size()-1;
    int shortIndex = shortStr.size()-1;
    int resultIndex = result.size()-1;
    //进位标志
    int carry = 0;

    //加运算
    while(shortIndex>=0){
        int add = longStr[longIndex--] - '0' + shortStr[shortIndex--] - '0' + carry;
        carry = add/10;
        result[resultIndex--] = add%10 + '0';
    }
    //最后是否进位
    if(carry > 0){
        result[resultIndex--] = carry + '0';
    }
    //截取从这个参数下标开始一直到结尾(把前面多余的0截掉)
    result = result.substr(resultIndex+1);
    return result;
}

string CalculateWays(unsigned int n)
{
    //也可以使用一个数组,把每次计算结果存进去
    if(n==1)
        return "1";
    if(n==2)
        return "2";
    string lastlast = "1";
    string last = "2";
    string result = "0";
    for(int i=3;i<=n;i++){
        result = BigNumAddString(lastlast,last);
        lastlast = last;
        last = result;
    }
    return result;
}

int main()
{
    int n;
    cin>>n;
    if(n<=0){
        cout<<"输入范围错误"<<endl;
    }
    else{
        cout<<CalculateWays(n);
    }

    return 0;
}

5 新知识

string和一些容器可以使用resize预分配空间,这样可以直接使用对象+[]形式赋值。

原文地址:https://www.cnblogs.com/Fflyqaq/p/12039743.html