剑指offer-斐波拉切数列+跳台阶+变态跳台阶(递归系列)

本文深入解析了多个经典算法问题,包括斐波那契数列的不同解法,跳台阶问题及其变种,以及矩形覆盖问题。通过递归、动态规划等方法,详细阐述了解题思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、斐波拉切数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39

解题思路:

参考了这篇博客:https://www.cnblogs.com/edisonchou/p/4752052.html

对于斐波拉切数列,我们都很熟悉,在学递归方法的时候都讲过这个经典的运用递归的算法。

所以一种通常的解题方法就是用递归。

1.递归,但是递归的时间复杂度相当高,因为它在递归的过程中会计算一些重复的步骤。

越靠下面的元素要都要计算更多的遍数。

代码1:

public class Solution {
    public int Fibonacci(int n) {
        if(n>39){
            System.out.println("n不能大于39!");
        }
        return Fib(n);
    }
    private int Fib(int n) {
        // TODO Auto-generated method stub
        if(n<=1){
            return(n==1?1:0);
        }
        return Fib(n-1)+Fib(n-2);
    }
}

 

2.从下往上顺序计算

这样可以避免计算上面这棵树中一些重复的节点。时间复杂度为o(n),耗时比递归方法减少了很多。

代码2:

public class Solution {
    public int Fibonacci(int n) {
        int[] init={0,1};
        if(n<2){
            return init[n];
        }
        int f_2=0;
        int f_1=1;
        int f_n=0;
        for (int i = 2; i <= n; i++) {
            f_n=f_2+f_1;
            f_2=f_1;
            f_1=f_n;   
        }
         
        return f_n;
 
    }
}

上图给出了两种方法的执行时间,可以看出递归的时间复杂度不是一般的大。

 

二、跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

如果只有n=1,则只有一种方法。

如果有n=2,则有两种方法,1+1或者2;

如果n>2,则第一次跳的时候有两种不同的选择,跳1台,则剩下的跳法与前面n-1台的一致。如果跳2台,则剩下的跳法与前面n-2台的一致。f(n)=f(n-1)+f(n-2).

所以此题的解法与上面解法一致。

代码:

public class Solution {
    public int JumpFloor(int target) {
        int[] init={1,2};
		if(target<=2){
			return init[target-1];
		}
		int t_2=1;
		int t_1=2;
		int t=0;
		for (int i = 3; i <=target; i++) {
			t=t_2+t_1;
			t_2=t_1;
			t_1=t;
			
		}
		return t;

    }
}

用数组存储前面序列的值:

public class Solution {
    public int JumpFloor(int target) {
        if(target<=2){
			return (target==2?2:1);
		}
		int[] ret=new int[target+1];
		ret[1]=1;
		ret[2]=2;
		for (int i = 3; i < ret.length; i++) {
			ret[i]=ret[i-2]+ret[i-1];	
		}		
		return ret[target];
    }
}

三、变态跳台阶

参考:https://blog.youkuaiyun.com/qq_35082030/article/details/66975094

题目描述

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

n=1时,有一种方法,f(1)=1;

n=2时,有两种方法,1+1,2,所以f(2)=2;

n=3时,如果第一次跳1,则剩下的跳法有f(2)种;第一次跳2,则剩下的跳法有f(1)种;第一次跳3。f(3)=f(2)+f(1)+1;

n=4时,如果第一次跳1,则剩下的跳法有f(3)种;第一次跳2,则剩下的跳法有f(2)种;第一次跳3,则剩下的有f(1)种跳法;第一次跳4。  所以f(4)=f(3)+f(2)+f(1)+1

……

设1=f(0),

则为n时,f(n)=f(n-1)+f(n-2)+…+f(2)+f(1)+f(0);

而            f(n-1)=       f(n-2)+…+f(2)+f(1)+f(0);上下相减,可得

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

实现1:线性操作

public class Solution {
    public int JumpFloorII(int target) {
        if(target==1){
            return 1;
        }
        int f=1;
        for(int i=1;i<target;i++){
            f*=2;            
        }
        return f;
        
    }
}

实现2:递归操作(不推荐)

public class Solution {
    public int JumpFloorII(int target) {
        if(target<=2){
            return (target==2?2:1);
        }
        return 2*(JumpFloorII(target-1));
         
    }
}

实现3:未化简之前(递归方法)

public class Solution {
    public int JumpFloorII(int target) {
        if(target<=2){
            return (target==2?2:1);
        }
        int sum=0;
        for (int i = 0; i <target; i++) {
            sum+=JumpFloorII(i);
        }
        return sum;
         
    }
}

 

 

对上面化简后的式子f(n)=2f(n-1)再次进行化简,

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

实现4:

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

 

4.跳台阶,三种方式

题目:一个人爬楼梯,一次可以爬1级,2级,5级,如果楼梯一共有N级,总共有多少种走法?

实现1:递归

public int  jump(int target){
	if(target==0) return 1;
	if(target==1) return 1;
	if(target==2) return 2;
	if(target<5){
		return jump(target-1)+jump(target-2);

	}else{
		return jump(target-1)+jump(target-2)+jump(target-5);
		
	}
}

实现2:DP

public int  jump2(int target){
	if(target<0) return 0;
	if(target==1) return 1;
	if(target==2) return 2;
	int[] dp=new int[target+1];
	dp[0]=1;
	dp[1]=1;dp[2]=2;
	if(target<=2){
		return dp[target];
	}
	for (int i = 3; i <=target; i++) {
		if(i<5){
			dp[i]=dp[i-1]+dp[i-2];	
		}else{
			dp[i]=dp[i-1]+dp[i-2]+dp[i-5];
		}
	}
	return dp[target];
}

 

四、矩形覆盖

题目描述

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

思路参考这篇博客:https://www.cnblogs.com/csbdong/p/5689674.html

如果竖着覆盖,则剩下的矩形覆盖方法有f(n-1)种。

如果横着覆盖,则与它对应位置的第二行也只能横着覆盖,则剩下的矩形的覆盖方法有f(n-2)种。

所以得出总的表达式:

n=1时,f(1)=1

n=2时,f(2)=2

n>2时,f(n)=f(n-1)+f(n-2)

得出的也是一个斐波拉切数列,实现方法与题目一一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值