《剑指offer》刷题——【递归循环】面试题10:斐波那契数列/青蛙跳台阶问题(java实现)

博客介绍了如何使用递归和循环解决斐波那契数列问题,并通过青蛙跳台阶的问题进行深入解析。文章讨论了递归效率问题,并提出改进方法,将递归转换为循环,降低时间复杂度至O(n)。同时,扩展到变态跳台阶和矩阵覆盖问题,发现这些问题与斐波那契数列的关联。
摘要由CSDN通过智能技术生成

一、题目描述

 求斐波那契数列的第n项:
 写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项,定义如下:
n=0, f(n)=0
n=1, f(n)=1
n>1, f(n)=f(n-1) + f(n-2)

二、解题思路

1. 书上常见解法,递归(效率低)

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

在这里插入图片描述
上面方法递归方式如上图所示,由图可看出,在这棵树中有很多节点是重复的,而且重复的节点数会随着n的增大而急剧增加,计算量也会增大。用这种递归方法计算的时间复杂度是以n的指数方式递增,因此面试过程中不建议使用

2. 改进递归,从下往上计算,把递归的算法用循环实现,时间复杂度O(n)

从下往上计算,首先根据 f(0) f(1) 算出 f(2),再根据 f(1) 和 f(2)算出 f(3)…以此类推就可以算出第n项

public class Solution {
    public int Fibonacci(int n) {
        if(n == 0)
            return 0;
        if(n == 1)
            return 1;
        int fibNMinusOne = 1;//第一个
        int fibNMinusTwo = 0;//第二个
        int fibN = 0;//和
        //遍历
        for(int i=2; i<=n; i++){
            fibN = fibNMinusOne + fibNMinusTwo;
            
            fibNMinusTwo = fibNMinusOne;
            fibNMinusOne = fibN;  
        }
         return fibN;    
    }
}

三、斐波那契数列应用——青蛙跳台阶问题

1. 题目描述

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

2. 解题思路

(1)如果只有1级台阶,那显然只有一种跳法;
(2)如果有2级台阶,就2种跳法(一种是分两次跳,每次跳1级;另一种是一次跳2级);
(3)如果有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)
    又上述分析,可看出,实际就是斐波那契数列。

3. 代码实现

public class Solution {
    public int JumpFloor(int target) {
        if(target == 1)
            return 1;
        if(target == 2)
            return 2;
        int MinusOne = 2;
        int MinusTwo = 1;
        int result = 0;
        for(int i=3; i<=target; i++){
            result = MinusOne + MinusTwo;
            MinusTwo = MinusOne;
            MinusOne = result;
        }
        return result;
    }
}

四、变态跳台阶

1. 题目描述

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

2. 解题思路

因为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)
f(n) = 2^2 f(n-2)

f(n) = 2^(n-1) f(1) = 2^(n-1)

3. 代码实现

public class Solution {
    public int JumpFloorII(int target) {
        return 1 << (target-1);//把一个数左移n位相当于把该数乘以2的n次方
    }
}

五、矩阵覆盖

1. 题目描述

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

2. 解题思路

在这里插入图片描述
(1)把 2X8的覆盖方法记为 f(8);
(2)用第一个 2x1的小矩形去覆盖大矩形去覆盖大矩形的最左边时有两种选择:

  • 横着放
  • 竖着放
    (3)当竖着放时,右边剩下 2x7的区域,记为 f(7)
    (4)当横着放时,当横着放在左上角,左下角就必须横着放一个 2x1的小矩形,而在右边还剩下 2x6 的区域,f(6)
    (5)因此,f(8) = f(7) + f(6)
    由上述分析可知,仍是菲波那切数列

3. 代码实现

public class Solution {
    public int RectCover(int target) {
        if(target <= 2)
            return target;
        int minusOne = 2;
        int minusTwo = 1;
        int result = 0;
        for(int i=3;i<=target; i++){
            result = minusOne + minusTwo;
            minusTwo = minusOne;
            minusOne = result;
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值