动态规划算法修炼

199 阅读4分钟

1. 动态规划

自底向上思想:我们直接从最底下,最简单,问题规模最小的 f(1) 和 f(2) 开始往上推,直到推到我们想要的答案 f(20),这就是动态规划的思路,这也是为什么动态规划一般都脱离了递归,而是由循环迭代完成计算

最优子结构:原问题的最优解,可以通过子问题的最优解获得

重叠子问题:消除了递归中出现的重叠子问题的重复计算

2. 动态规划的三大步骤

第一步:定义数组元素的含义
第二步:找出数组元素之间的关系式,也就是递推公式或者说状态转移方程
第三步:找出初始值

有了初始值,并且有了数组元素之间的关系式,那么我们就可以得到 dp[n] 的值了,而 dp[n] 的含义是由你来定义的,你想求什么,就定义它是什么,这样这道题也就解出来了

3. 递归题

3.1 小青蛙跳台阶

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

分析过程

第一步dp[n]的含义,想求什么就定义它是什么。所以这里定义跳n级台阶有dp[n]种跳法

第二步:思考对于这道题,由于情况可以选择跳一级,也可以选择跳两级,所以青蛙到达第 n 级的台阶有两种方式:

一种是从第 n-1 级跳上来

一种是从第 n-2 级跳上来

由于我们是要算所有可能的跳法的,所以有 dp[n] = dp[n-1] + dp[n-2]

试想10级台阶跳法是dp[10],10级台阶两种情况,一种是第8级台阶跳上去也就是dp[8];另一种是从第9级台阶跳上去也就是dp[9]。跳法状态转移方程dp[10] = dp[9] + dp[8]

第三步:找初始条件。当 n = 1 时,dp[1] = dp[0] + dp[-1],而我们是数组是不允许下标为负数的,所以对于 dp[1],我们必须要直接给出它的数值,相当于初始值,显然,dp[1] = 1。一样,dp[0] = 0.(因为 0 个台阶,那肯定是 0 种跳法了)。于是得出初始值:

dp[0] = 0. dp[1] = 1. 即 n <= 2 时,dp[n] = n

// 代码
function Fun(n){
	let dp = []
    // 初始值
    dp[1] = 1
    dp[2] = 2
    
    // 数组元素关系式
    for (let i=2; i<= n; ++i){
    	dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
}

3.2 二维数组DP

题目:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。问总共有多少条不同的路径?

分析过程

第一步:定义到达 m x n网格位置,也就是右下角,需要dp[i][j]条路径

第二步:找数组元素关系式,试想到达m*n右下角位置,有两条路可以到达,一种是从dp[i-1][j]向下走一步到达,另一种是从dp[i][j-1]向右走一步到达;所以dp[i][j] = dp[i-1][j] + dp[i][j-1]

第三步:找初始条件;当 dp[i] [j] 中,如果 i 或者 j 有一个为 0,那么还能使用关系式吗?答是不能的,因为这个时候把 i - 1 或者 j - 1,就变成负数了,数组就会出问题了

dp[0] [0….n-1] = 1; // 相当于最上面一行,机器人只能一直往左走

dp[0…m-1] [0] = 1; // 相当于最左面一列,机器人只能一直往下走

int Fun(m, n){
   if (m <= 0 || n <= 0) {
        return 0;
    }

    int dp[][] = new int[m][n]; 
      
    // 初始化
    for(int i = 0; i < m; i++){
      dp[i][0] = 1;
    }
    for(int i = 0; i < n; i++){
      dp[0][i] = 1;
    }
    
    // 推导出 dp[m-1][n-1]
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[i][j] = dp[i-1][j] + dp[i][j-1];
        }
    }
    return dp[m-1][n-1];
}

参考系列

mp.weixin.qq.com/s/pg-IJ8rA1…

labuladong.gitbook.io/algo/di-lin…

juejin.cn/post/691777…

juejin.cn/post/684490…