LeetCode 70. Climbing Stairs 自顶向下记忆化搜索,自底向上重叠子问题动态规划

70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Note: Given n will be a positive integer.

题意

爬楼梯案例。需要n步能到达楼梯的尽头
每一个你可以选择爬1阶或者2阶楼梯。有多少种方案可以爬到顶端
给定的n是一个正整数

思路1

类似斐波那契数的解法
分析f[i]表示i个台阶有多少种爬的方式
f[1] = 1; f[2] = 2;
f[n] = f[n-1]+f[n-2]典型的递归结构
求n阶台阶需要知道爬n-1阶和n-2阶台阶,有多少种爬的方式。以此递推,不断向下查找。自顶向下
直到递归结束条件:n==1或n==2时
这里写图片描述

代码1

//算法复杂度:O(2^n)指数级
class Solution {
private:
    int res;
    //f(1)=1, f(2) = 2;  f(n) = f(n-1)+f(n-2)
    //统计走第i个楼梯有多少种可能
    int calcStairs(int i)
    {
        if(i == 1)
            return 1;
        if(i == 2)
            return 2;        
        res = calcStairs(i-1)+calcStairs(i-2);        
        return res;
    }
public:    
    int climbStairs(int n) {        
        //n个台阶,范围是[0...n],总共有n+1个元素
        vector<int> count(n+1,-1);
        //类似于斐波那契数,解法1,自底向上,从子问题开始
        res = calcStairs(n);    
        return res;
    }
};
  • 结果当然是超时
    这里写图片描述

思路2

通过观察思路1,发现有大量的重复计算,即重叠的子问题。可以使用记忆化方式,减少进入递归的次数,通过查表的方式,直接获取结果。对于相同的台阶数,只计算一次。这样能极大的加快算法
这里写图片描述

代码2

class Solution {
private:

     vector<int> count;
    //f(1)=1, f(2) = 2;  f(n) = f(n-1)+f(n-2)
    //直接使用递归超时,未做任何优化
    //统计走第i个楼梯有多少种可能
    int calcStairs(int i)
    {
        if(i == 1)
            return 1;
        if(i == 2)
            return 2;
        if(count[i] == -1)
        {
            count[i] = calcStairs(i-1)+calcStairs(i-2);    
        }


        return count[i];
    }
public:

    int climbStairs(int n) {
        int res;
        //n个台阶,范围是[0...n],总共有n+1个元素,来记忆n个台阶可走的可能
        count = vector<int>(n+1,-1);
        //类似于斐波那契数,解法1,自底向上,从子问题开始
        res = calcStairs(n);    
        return res;
    }
};
  • 获得了一个AC

这里写图片描述

思路3

之前的思路都是自顶向下,递归的向下去寻找。通过分析发现,n个台阶可能的走法,实际上可以转换为一个子问题的求解,当子问题得到解,那么将子问题的解合起来,也就是整个问题的解。
这样的方法称之为动态规划,自底向上。

代码3

class Solution {
public:
    int climbStairs(int n) {
        //n个台阶,范围是[0...n],总共有n+1个元素
        vector<int> count(n+1,-1);
        //类似于斐波那契数,解法1,自底向上,从子问题开始
        count[1] = 1;
        count[2] = 2;
        for(int j=3;j<=n;j++)
        {
            count[j] = count[j-1]+count[j-2];
        }

        return count[n];

    }
};
  • 这样的代码比起思路1和2简洁了很多。通过求解子问题来达到全局解
    这里写图片描述

总结

  • 动态规划:将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。
  • 这里写图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值