斐波那契数列及其变形


  • 题目描述:

写一个函数,输入n,求斐波那契数列的第n项。

  • 分析:

    斐波那契数列在递归的学习时经常被拿来做例子,当剑指offer上看到这个题的时候,我就直接用递归写了,然后发现了问题,调用栈空间太多。这就是递归方法的一个缺陷,虽然简单容易理解,然而效率上却为难了计算机。所以还是以循环来实现:

    long long Fibonacci(unsigned int n)
    {
    	int result[2] = {0,1};
    	if(n < 2)
    		return result[n];
    	// 当n>2时
    	long long first = 1;
    	long long second = 0;
    	long long fib = 0;
    	for(unsigned int i = 2; i <= n; ++i)
    	{
    		fib = first + second;
    		second = first;
    		first = fib;
    	}
    	return fib;
    }
    

    其实斐波那契数列的循环实现很容易写出来,就根据斐波那契的定义来写就好了:第n项为其前两项的和,只要从头开始求每一项向后推就可以得到结果。

变形1:下边是斐波那契数列的一个变形,青蛙跳台阶。

  • 题目描述:

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

  • 分析:

    其实和斐波那契函数是一个道理,如果一次它想跳到第n级台阶,因为一次只能跳一级或者两级,所以它一定是从第n-1级台阶,或者是n-2级台阶跳上来的,所以可以分解为求f(n-1)+f(n-2)。
    代码:

    class Solution {
    public:
    	int jumpFloor(int n) {
        	int result[2] = {1,2};
        	if(n < 3 && n > 0)
            	return result[n-1];
        
        	int first = 2;
        	int second = 1;
        	int fib = 0;
        	for(int i = 3; i <= n; ++i){
           		fib = first + second;
        		second = first;
        		first = fib;
      		}
        	return fib;
    	}
    };
    

变形2:

  • 题目描述:

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

  • 分析:

    我这种凡人,只想到了凡人的方法。。
    每个台阶都可以直接跳上去,也可以从前边每个台阶跳上来。所以每个台阶的可能性都是把其前边所有台阶的可能性加起来,再加1(就是直接跳上去的可能性)。

    f(n) = f(n-1)+f(n-2)+f(n-3)+...+f(1)+1;
    f(n-1) = f(n-2)+f(n-3)+f(n-4)...+f(1)+1
    两式相减,得到f(n) = 2f(n-1);
    好吧,等比数列,f(n) = 2^(n-1)

    接下来是牛客上看到的,大神的思路:

    每个台阶都有跳与不跳两种情况(除了最后一个台阶),最后一个台阶必须跳。所以共用2^(n-1)中情况

    不得不说言简意赅,跟我等找规律的不一样。

    再接下来是代码,我的思路:

    class Solution {
    public:
    	int jumpFloorII(int number) {
    		if(number > 0){
    		// 用一个长度为number的vector把每一级台阶的可能性都记录下来
    			vector<int> v(number,0);
    			v[0]=1;
    		// 每个台阶都是把其前边所有台阶的可能性加起来再加一
    			for(int i = 1; i < number; ++i){
    				for(int j = 0; j < i; ++j){
    					v[i] += v[j]; 
    				}
    				++v[i];
    			}
    			return v[number-1];
    		}
    		else
    			return 0;
    	}
    };
    

    又有一行代码解决问题的大神:

    // 1左移number-1位,即2^(number-1)
    return 1 << --number;
    

变形3:

  • 题目描述:

我们可以用2x1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2x1的小矩形无重叠地覆盖一个2xn的大矩形,总共有多少种方法?

  • 分析:

    举例观察可知还是斐波那契

    class Solution {
    public:
    	int rectCover(int number) {
    		if(number < 1)
    			return 0;
    		
    		int result[2] = {1,2};
    		if(number < 3)
    			return result[number-1];
    		
    		int first = 2;
    		int second = 1;
    		int num = 0;
    		for(int i = 3; i <= number; ++i){
    			num = first + second;
    			second = first;
    			first = num;
    		}
    		return num;
    	}
    };
    
原文地址:https://www.cnblogs.com/Bill-LHR/p/6769401.html