动态规划(2)——另一个简单的例子


上一节中我们讲了一个炒鸡简单的动态规划的例子,主要讲述了动态规划的思路,即我们是怎么从暴力求解,进入到动态规划的思路的。本节中我们来关注另一道炒鸡简单和典型的动态规划的题。

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/climbing-stairs

我在拿到这道题的时候,第一反应应该是这不就是高中的排列组合么,确实,这就是一道排列组合题,但是深入一想,啧,这个排列组合貌似有丢丢复杂,没法在第一时间得到f(n)的公式。此时再转念一想,要不用暴力求解的办法,暴力求解不是不可以,可以用递归实现。

int ans = 0;
void temp(int n){
      if(n==0) {
          ans++;
          return;
      }
      if(n<0)
          return;
      temp(n-1);  // 走一步
      temp(n-2);  //走两步
}

但是很显然,上述暴力求解是经过一步一步的试探,最终得到了总共有几种走法,这样一来势必会有很多重复计算的过程,而且,再n很大的时候,递归深度太大,不现实,此处可以记住一个小技巧,也是在上一个小节中提到的,能用递归解决的问题,很可能就能用动态规划解决。

动态规划的核心是保存已经计算过的结果,通过已经计算出来的结果去推断出下一个状态的结果,翻译成人话就是,动态规划的核心就是状态转移方程。和递归相比,由于其能够存储中间结果,因此,有着很好的时间复杂度。

那么,这道题用动态规划的思想,如何解决呢? 或者说,他的状态转移方程是什么呢?我们假设,如果我们知道了状态 i 的路径 step1,那么 i+1 的路径会是怎样的呢?首先我们思考,状态 i+1 可以从哪些状态转移过来,很简单状态 i 向上买一步就可以到达状态 i+1,也就是说,在这种情况下( i 向上迈一步到达状态 i+1 ),状态 i+1 的到达路径和状态 i 的路径完全一致,即所有的路径再迈一步而已。题设中还有一种方式,即,迈两步,那么也就是说,状态 i+1 也可以由状态 i-1 迈两步到达,和之前分析的,在这种情况下,状态 i+1的路径和状态 i-1 的路径完全一致。那么我们可以得到,状态 i+1 是由状态i 和状态 i-1 到达,即,f( i+1 ) = f( i ) + f( i-1 );我们又可知, f( 1 ) = 1(迈一步就完了), f ( 2 ) = 2(两个一步,和一个两步),那么可以有以下代码。

public int climbStairs(int n) {
        switch (n){
            case 1:return 1;
            case 2:return 2;
            default:{
                int[] dp = new int[n+1];
                dp[1] = 1;
                dp[2] = 2;
                for(int i=3; i<=n;i++){
                    dp[i] = dp[i-1] + dp[i-2]; // 状态 i 可以由 i-1 迈一个台阶到达,也可以由i-2迈两个台阶到达。
                }
                return dp[n];
            }
        }
    }

事实上,这一类问题有一个基于DP的通解,即加入一个step变量,此step变量指的是,最多一次能走几个台阶。显然step>=1,再此题中,step是2。

那么其通解可以由一下代码给出:

public int climbStairs(int n) {
        switch (n){
            case 1:return 1;
            case 2:return 2;
            default:{
                int[] dp = new int[n+1];
                dp[1] = 1;
                dp[2] = 2;
                int step = 2;
                for(int i=3; i<=n;i++){
                    for (int j=1;j<=step;j++)
                        dp[i] += dp[i-j];   // 在i-j的状态上走j步,就到了i的状态。
                }
                return dp[n];
            }
        }
    }

当然了,此题除了动态规划外,还可以用数学的方式们直接计算出公式,这种算法具备最佳的复杂度,但是也更难理解。

优质内容筛选与推荐>>
1、pyqt5 appendPlainText多添加换行符的解决办法
2、媒体云平台
3、ASP.NET MVC学习之控制器篇
4、白孩儿--一个网上流传的故事[生活感悟]
5、算法学习(一) -- 基本算法


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn