动态规划三要素
1、最优子问题
F(10)=F(9)+F(8),就是F(10)的最优子问题,局部贪心完美的将问题分解,如果得到的F(9)和F(8)都是最优解,F(10)一定也是最优解。
2、边界条件
分解到最后一定变成了规模最简单的问题,即F(1)和F(2)这两个问题,不能再分解,不过没关系,他们很简单,用你的小心心算就OK了。
3、状态转移方程(DP方程)
假设状态转移方程为F(n)=F(n-1)+F(n-2),这就是解决问题的核心,使得状态能够动起来。
备忘录
在动态规划过程中,类似于回溯法中对中间结果进行存储,确保已计算过的结果就不再重复计算,减少运算量。
动态规划和分治法的区别
动态规划计算的过程中有重复计算的部分,这部分我们把它记录下来,避免重复计算,如果没有这部分重复,它就退化成分治算法了。
核心(DP方程)
1、最优子问题
DP方程是从最优子问题中鬼哪来的,什么算是最优子问题呢?就是不管之前的决策是否是最优决策,都必须保证从现在开始的决策是在之前的基础上最优,具体的说,我们默认F(8)、F(9)是最优,在此基础上,得到最优解F(10)。
2、不影响后续决策
由于上一条我们看到,如果F(8)的决策会影响到F(9)和F(10),那么F(10)=F(8)+F(9)就不成立了。所以一定要保证,每个阶段的决策仅受之前决策的影响,但不影响之后的决策。
最长子序列问题
给出字符串S1和S2,判断S1和S2中最长的相等字符串长度是多少。
解题逻辑
本题主要考虑两种场景
1、字符串相等时,F(n)=F(n-1)+1
2、字符串不相等时,F(n)=F(n-1)
动态规划代码实现
private static int theLongestSubSequence(String s1, String s2) {
int n = s1.length(), m = s2.length();
int[][] dp = new int[n + 1][m + 1];
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
dp[i][j] = 0;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = dp[i - 1][j] > dp[i][j - 1] ? dp[i - 1][j] : dp[i][j - 1];
}
}
}
return dp[n][m];
}