剑指offer07-斐波那契数列

194 阅读4分钟

斐波那契数列

题目描述

写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项 : 0 1 1 2 3 5 8......

思路

  1. 基于递归
  2. 把递归的算法用循环实现
  • 递归虽然有简介的优点,但它也有显著的缺点。递归由于是函数调用自身,而函数调用是有时间和空间消耗的:每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址及临时变量,而且往栈里压入数据和弹出数据都需要时间。因此本题递归实现效率不如循环。另外,本题中,采用递归方法会有很多计算都是重复的,从而对性能带来很大的负面影响。递归的本质是把一个问题分解成两个或多个小问题。如果多个小问题存在相互重叠的部分,就存在重复的计算。通常应用动态规划解决问题时采用递归思路分析问题,但由于递归分解的子问题中存在大量的重复,因此采用自下而上的循环来实现代码。除效率之外,递归还有可能引起更严重的问题:调用栈溢出。每一次函数调用都需要在内存栈中分配空间,而每个进程的栈的容量是有限的。当递归调用的层级太多时,就会超出栈的容量,从而导致调用栈溢出。

程序(java)

    /**
     * code1
     * 递归
     */
     class Solution4 {
    public int Fibonacci(int n) {
        int array[] = new int[n+2];
        if(n==0){
            return 0;
        }
        if(n==1){
            return 1;
        }
        return Fibonacci(n-1)+Fibonacci(n-2);
    }
}
    /**
     * code2
     * 把递归用循环实现
     * 两个局部变量
     * 时间复杂度:O(n)
     */
public class Solution {
    public int Fibonacci(int n) {
        if(n==0){
            return 0;
        }
        if(n==1){
            return 1;
        }
        int sum=1;
        int preSum=1;
        while(n-->2){
            sum += preSum;
            preSum=sum-preSum;
        }
        return sum;
    }
}

斐波那契数列应用

1青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法。
思路
  • 将n级台阶时的跳法看作n的函数,记为f(n)。当n>2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);二是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。因此,n级台阶的不同跳法的总数f(n)=f(n-1)+f(n-2)。
程序
    /**
     * code1
     * 把递归用循环实现
     * 两个局部变量
     * 非严格斐波那契数列:0 1 2 3 5 8......
     * 时间复杂度:O(n)
     */
public class Solution {
    public int JumpFloor(int target) {
        if(target==0){
            return 0;
        }
        if(target==1){
            return 1;
        }
        if(target==2){
            return 2;
        }
        int sum=2;
        int preSum=1;
        while(target-->2){
            sum += preSum;
            preSum=sum-preSum;
        }
        return sum;
    }
}

2矩形覆盖

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

矩形覆盖

思路
  • 将2*n的大矩形的覆盖看作n的函数f(n)。当n>2时,用第一个2*1的小矩形去覆盖大矩形最左边的时候有两种选择:竖着放或者横着放。当竖着放的时候,右边还剩下2*(n-1)的区域,这种情形下的覆盖方法记为f(n-1)。当横着放的时候。2*1的小矩形横着放在左上角,左下角也必须横着放一个,而在右边还剩2*(n-2)的区域,这种情形下的覆盖方法记为f(n-2)。因此f(n)=f(n-1)+f(n-2)。
程序
    /**
     * code1
     * 把递归用循环实现
     * 两个局部变量
     * 非严格斐波那契数列:0 1 2 3 5 8......
     * 时间复杂度:O(n)
     */
public class Solution {
    public int JumpFloor(int target) {
        if(target==0){
            return 0;
        }
        if(target==1){
            return 1;
        }
        if(target==2){
            return 2;
        }
        int sum=2;
        int preSum=1;
        while(target-->2){
            sum += preSum;
            preSum=sum-preSum;
        }
        return sum;
    }
}

3变态跳台阶

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