【剑指offer】变态跳台阶(贪心)/ 跳台阶(递归)

变态跳台阶

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

设f[i] 表示当前跳到第 i 个台阶的方法数。那么f[n]就是所求答案。
f(n) = f(n - 1) + … + f(2) + f(1)。递归的终止条件为n 为 0的时候,我们返回1。
1.递归

class Solution:
    def jumpFloorII(self, number):
        if number == 0:
            return 1
        cnt = 0
        for i in range(number):
            cnt += self.jumpFloorII(i)
        return cnt

2.数学
f(n)=f(n-1)+f(n-2)+…+f(1)
f(n-1)=f(n-2)+…f(1)
相减得:f(n)=2*f(n-1)

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

跳台阶

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

1.递归

class Solution {
public:
    int jumpFloor(int number) {
        //n级台阶,下台阶
        //要么n-1,要么n-2
        //f[n]=f[n-1]+f[n-2]
        //初值f[0]=f[1]=1
        if(number<=1) return 1;
        return jumpFloor(number-1) + jumpFloor(number-2);
    }
};

优点,代码简单好写,缺点:慢,会超时
时间复杂度:O(2^n)
空间复杂度:递归栈的空间

2.记忆化搜索
在这里插入图片描述
通过图会发现,方法一中,存在很多重复计算,因为为了改进,就把计算过的保存下来。
那么用什么保存呢?一般会想到map, 但是此处不用牛刀,此处用数组就好了。

class Solution {
public:
    int jumpFloor(int n) 
    {
        vector<int> dp(45, -1); // 因为答案都是>=0 的, 所以初始为-1,表示没计算过
        return Fib(n, dp);
    }
    int Fib(int n, vector<int>& dp)
    {
        if(n<=1) return 1;
        if(dp[n]!=-1) return dp[n];
        return dp[n] = Fib(n-1, dp) + Fib(n-2, dp);
    }
};

时间复杂度:O(n), 没有重复的计算
空间复杂度:O(n)和递归栈的空间

3.动态规划
如果想让空间继续优化,那就用动态规划,优化掉递归栈空间。
方法二是从上往下递归的然后再从下往上回溯的,最后回溯的时候来合并子树从而求得答案。
那么动态规划不同的是,不用递归的过程,直接从子树求得答案。过程是从下往上。

class Solution {
public:
    int jumpFloor(int n) 
    {
        vector<int> dp(n+1, 0);
        dp[0] = dp[1] = 1;
        for (int i=2; i<=n; ++i) 
        {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
};

时间复杂度:O(n)
空间复杂度:O(n)

继续优化
发现计算f[5]的时候只用到了f[4]和f[3], 没有用到f[2]…f[0],所以保存f[2]…f[0]是浪费了空间。
只需要用3个变量即可。

class Solution {
public:
    int jumpFloor(int n) 
    {
        if (n == 0 || n == 1) return 1;//return n也能调试通过?为啥
        int a = 1, b = 1, c;
        for (int i=2; i<=n; ++i) //只需要用3个变量
        {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }
};

AcWing 821. 跳台阶

题目描述:
一个楼梯共有n级台阶,每次可以走一级或者两级,问从第0级台阶走到第n级台阶一共有多少种方案。

输入格式
共一行,包含一个整数n。

输出格式
共一行,包含一个整数,表示方案数。

数据范围
1≤n≤15

样例
输入样例:
5
输出样例:
8

动态规划入门题

第0级台阶到第1级台 只有一种方法 上1级台阶
第0级台阶到第2级台 有两种方法 1种是0-2 上2级台阶 1种是上到1级台阶 再上2级台阶
第0级台阶到第3级台 有两种方法 1种是0-2 再2-3 1种是0-1 1-3 (其中0-1 1-2 2-3已经包含在前面的方法中了)

逆向来看就是 n台阶的方案数量 = n-1台阶方案数量 + n-2的方案数量

#include <iostream>
using namespace std;

int arr[20];
int main()
{
    int n;
    cin >> n;
    arr[1] = 1; arr[2] = 2;
    for(int i = 3;i <=15;i++){
        arr[i] = arr[i-1]+arr[i-2];
    }
    cout << arr[n];

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值