剑指offer-9.斐波那契数列 、青蛙跳台阶

斐波那契数列

题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39

这里写图片描述

1、递归的方法:
直观、但是存在大量重复计算,时间复杂度以n 的指数方式增长:
这里写图片描述

public class Solution {
    public int Fibonacci(int n) {
        if(n==0){
            return 0;
        }
        if(n==1){
            return 1;
        }
        return Fibonacci(n-1)+Fibonacci(n-2);
    }
}

2、非递归方法:
从下往上计算,先根据 f(0) 和 f(1) 计算 f(2) ,再根据 f(1) 和 f(2) 计算 f(3) … 依次类推 就能算出第n项。时间复杂度 O(n)

public class Solution {
    public int Fibonacci(int n) {
        if(n==0){
            return 0;
        }
        if(n==1){
            return 1;
        }
        int a=0;
        int b=1;
        int result=0;
        for(int i=2;i<=n;i++){
            result=a+b;
            a=b;
            b=result;
        }
        return result;
    }
}

青蛙跳台阶

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

题解:
如果只有1级台阶,那么显然只有一种跳法;
如果有2级台阶,就有两种跳法,一种每次跳1级,另一种一次跳2级。

把 n 级台阶时跳法看成 n 的函数, f(n) 。当 n>2 时,第一次跳有两种不同选择,一是第一次只跳1级,此时跳法总数就等于剩下的 n-1 级台阶的跳法总数,即 f(n-1); 另一种选择是一次跳2级,此时跳法数目等于后面剩下的 n-2 级台阶的跳法总数,即为 f(n-2) 。所有 f(n)=f(n-1)+f(n-2) . 这实际上就是斐波那契数列。

它实际上也是动态规划。

确定状态: f(n) 表示跳上 n 级台阶的跳法数
起始状态是: f[1]=1
终止状态是:f[target]
状态转移方程: f[i]=f[i-1]+f[i-2]

由于 f[i] 只跟 i-1 和 i-2 相关,所有可以用3个变量记录,不用申请数组,即为上题的那种写法。

public class Solution {
    public int JumpFloor(int target) {
        if(target<=0){
            return 0;
        }
        if(target==1){
            return 1;
        }
        int[] f=new int[target+1];//f[i] 表示跳i 级台阶,有多少种跳法
        f[1]=1;
        f[2]=2;
        for(int i=3;i<=target;i++){
            f[i]=f[i-1]+f[i-2];
        }
        return f[target];
    }
}

变态跳台阶

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

题解:
用数学归纳法,可以证明 f(n) = 2 n 1

简单分析:
因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+…+f(1)
因为f(n-1)=f(n-2)+f(n-3)+…+f(1)
所以f(n)=2*f(n-1)

public class Solution {
    public int JumpFloorII(int target) {
        if(target<=0){
            return 0;
        }
        return (int)Math.pow(2,target-1);
    }
}

矩阵覆盖

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

题解:
当 n=8 时,放第一个的时候,可以竖着放或横着放,当竖着放的时候,右边剩下 2*7 的区域,当横着放时,右边剩下 2*6 的区域。所有 f(8)=f(7)+f(6). 任然是费波那西数列数列,代码一模一样。

public class Solution {
    public int RectCover(int target) {
        if(target<=0){
            return 0;
        }
        if(target==1){
            return 1;
        }
        int[] f=new int[target+1];//f[i] 表示覆盖 2*i 的矩阵的方法数
        f[1]=1;
        f[2]=2;
        for(int i=3;i<=target;i++){
            f[i]=f[i-1]+f[i-2];
        }
        return f[target];

    }
}

猜你喜欢

转载自blog.csdn.net/zxm1306192988/article/details/80824588
今日推荐