zoukankan      html  css  js  c++  java
  • 斐波那契数列及其变形


    • 题目描述:

    写一个函数,输入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;
      	}
      };
      
  • 相关阅读:
    element表格添加序号
    ZOJ 3822 Domination(概率dp)
    HDU 3037(Lucas定理)
    HDU 5033 Building(单调栈维护凸包)
    HDU 5037 Frog(贪心)
    HDU 5040 Instrusive(BFS+优先队列)
    HDU 5120 Intersection(几何模板题)
    HDU 5115 Dire Wolf(区间dp)
    HDU 5119 Happy Matt Friends(dp+位运算)
    C++ string详解
  • 原文地址:https://www.cnblogs.com/Bill-LHR/p/6769401.html
Copyright © 2011-2022 走看看