动态规划
1.题目特点
(1)计数
- 有多少种方式走到右下角
- 有多少种方法选出k个数使得和是Sum
(2)求最大最小值
- 从左上角走到右下角路径的最大数字和
- 最长上升子序列长度
(3)求存在性
- 取石子游戏,先手是否必胜
- 能不能选出k个数使得和是sum
例题: Coin Change
动态规划解题步骤
- 确定状态
- 两个意识:最后一步 & 子问题
(1)最后一步:得出的最后结果一定是最优结果。通过最优结果去反推前面的结果
(2)子问题:通过最后的结果去反推前面的各个子问题
(3)通过子问题+最后结果,推导策略的各种分支状态。找到满足条件的状态 — 要求硬币数最少
- 初识条件和边界情况
- 在确定了状态方程后,需要给定状态方程开始迭代的数值(初识条件)
- 当状态转移方程无法计算出初值,但是又依赖于初值进行迭代时,需要自己定义
- 在确定了状态方程后,需要给定状态方程开始迭代的数值(初识条件)
- 计算顺序
- 当需要计算左边的时候,所有右边的值都已经求得
- 小结
硬币问题代码:LeetCode—322: Coin Change
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
// 排序保证大的在后面
Arrays.sort(coins);
// 初识条件
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
// Integer.MAX_VALUE 再加一会变成负数
dp[i] = Integer.MAX_VALUE - 1;
// 由于coin数组的大小不定,因此要进行遍历
for (int j = coins.length - 1; j >= 0; j--) {
if (i >= coins[j]) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] == Integer.MAX_VALUE - 1 ? -1 : dp[amount];
}
机器人路径总数问题:LeetCode-62:Unique Path
public int uniquePaths(int m, int n) {
if (m == 1 || n == 1) return 1;
int[][] dp = new int[m][n];
dp[0][0] = 1;
// 执行初始化
for (int i = 1; i < m; i++) dp[i][0] = 1;
for (int i = 1; i < n; i++) dp[0][i] = 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];
}
存在性规划问题:
青蛙跳台
1.最后一步
2.子问题
3.转移方程
状态方程小结:
数字和最大最小题型:状态方程是f(n) = min(f(n-1),f(n-i) +g(i))等等
累积的题目状态方程:f(n) = f(i-2) +f(i-1) --类比
而存在性题目状态方程:f(n)= (f(i) && 条件) || (f(i - 1) && 条件)……
4.计算顺序