前言
动态规划(DP)是计算机编程算法中非常重要的一个知识点,无论是校招 社招,面试官也经常喜欢出此类的编程题来考察面试者的编程能力, 这篇博客主要是概述一下dp的主要思想 然后重点归纳一下动态规划相关经典问题的讲解。
DP基础知识
DP简单可以总结为“一个模型三个特征”。
- “一个模型”是指动态规划适合解决的问题的模型,也就是多阶段决策最优解模型(这个模型同时也是回溯 贪心解决问题的模型)。一般用动态规划解决最优问题时,解决问题需要经历多个决策阶段。每个决策阶段都对应着一组状态。然后我们寻找一组决策序列,经过这组决策序列,能够产生最后在那个期望求解的最优值。
- “三个特征”指的是:最优子结构、无后效性和重复子问题。
牢记,dp问题最重要的核心写出状态转移方程
状态转移方程法的思路:找最优子结构——写状态转移方程——将状态转移方程翻译成代码
上面的知识归纳 读者可以看看后 留个印象,下面我们来看看具体的习题。
经典习题
杨辉三角的最短路径问题
求解 从第一层走到最后一层的最短路径长度是多少
如上面左图所示,也就是我们常见的杨辉三角结构, 在计算机的存储表示中 他的形式如同上面右图所示。每一个节点的运动方向在图中显示, 根据节点数值的运动方向,我们可以比较清晰的概括出该问题的dp状态转换方程dp[i][j]。
代码如下:
public int shortestPath(int[][] array) {
//首先定义一个二维的状态转换数组 中间的值存储的是当前走过的路径
int[][] dp = new int[array.length][array[array.length - 1].length];
dp[0][0] = array[0][0];
//DP的过程如下: 画图便能得到
// 第一列元素对应的状态值只会是运动方向向下得到的 states[i][0]=states[i-1][0]+tri[i][0]
//中间位置的states[i][j] 可以由[i-1][j-1]和[i-1][j]较小的值得到
// 每一行的最后一个元素[i][j]由[i-1][j-1]得到
for (int i = 1; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (j == 0) dp[i][j] = dp[i - 1][j] + array[i][j];
else if (j == array[i].length - 1) dp[i][j] = dp[i - 1][j - 1] + array[i][j];
else dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + array[i][j];
}
}
//输出最小值 也就是二维数组中最后一行中的最小值
int min = Integer.MAX_VALUE;
for (int j = 0; j < dp[array.length - 1].length; j++) {
min = Math.min(min, dp[array.length - 1][j]);
}
return min;
}
左上到右下的最短路径
一个二维数组中,每个节点的运动方向只能是向下或者向右。求解从左上到右下的最短路径:
因为和上一题杨辉三角的最短路径相似,这里不再进行过多赘述。 dp状态转换方程如图所示。
public int shortestPath(int[][] a) {
int n = a.length, m = a[0].length;
int[][] states = new int[n][m]; 定义状态转换数组
//开始写DP过程
//大多数位置的值states[i][j] 由min(states[i-1][j],states[i][j-1])得到
//第一行只能往右移动 第一列只能向下移动
states[0][0] = a[0][0];
for (int i = 1; i < m; i++) {
states[0][i] = states[0][i - 1] + a[0][i]; //第一行
}
for (int i = 1