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

Posted establish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划——另一个简单的例子相关的知识,希望对你有一定的参考价值。

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

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

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

以上是关于动态规划——另一个简单的例子的主要内容,如果未能解决你的问题,请参考以下文章

谈谈动态规划的本质

Python之动态规划算法

JC3 简单动态规划

动态规划经典例子——编辑距离问题

控制与人生: 上篇-规划篇 动态规划

分治算法与动态规划的区别