码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-10-03 23:54:02      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:复杂度   需要   problems   除了   暴力   多少   方式   code   span   

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

假设你正在爬楼梯。需要 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];
            }
        }
    }

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

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

标签:复杂度   需要   problems   除了   暴力   多少   方式   code   span   

原文地址:https://www.cnblogs.com/establish/p/11621097.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!