一、题目描述:
二、思路分析:
这篇文章主要是将前文讲过的动态规划一般思路进行一个补充,因为有时候似乎状态转移方程格外难写,很多时候都明明知道这是动态规划,但就是写不出来状态转移方程。
本文着重讲下第二步:确定状态
我们讲确定状态进一步展开为状态表示和状态计算
状态表示
状态表示就是状态是什么,即dp[i][j]代表了满足条件i和满足条件j的最大/最小/的和。
在这道题中,dp[i][j]就是指字符串1前i个长度,和字符串2前j个长度的子序列的最大长度。
状态计算
状态计算就是一步步算出如何得到dp[i][j],你当然可以在草纸演算过程,大胆假设,最后删减成答案
如何得到这种表达如果让你困惑,可以改为从前面哪几个子问题得到,或者答案由几种可能构成。
在这道题中,我们想到dp[i][j],肯定和dp[i - 1][j] 、dp[i][j - 1]、dp[i - 1][j - 1]有关,而对于str[i]和str[j] 也无非只有str[i] == str[j] 、str[i] != str[j]两种可能。
看起来两种可能的比较好分析,
str[i] == str[j]时,dp[i][j] = dp[i - 1][j - 1] + 1str[i] != str[j]时,由于dp[i - 1][j - 1]同时也是dp[i - 1][j]所需要考虑的,因此不再将dp[i - 1][j - 1]纳入计算。当str[i] != str[j]时,最长的子序列只剩下包含str1[i]或者str2[j]两种可能(都不包含的可能 在刚才被排除了)-
我们大胆假设str1[i]为最长子序列的尾部,而str2[j]不是最长子序列的尾部,那就相当于str2[j]时没用的,此时dp[i][j] == dp[i][j - 1],因此我们可以用dp[i][j - 1]作为dp[i][j]的一种可能
-
那么此时状态转移方程就呼之欲出了:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if(str1[i] == str2[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
三、AC 代码:
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m = text1.size();
int n = text2.size();
int dp[m + 1][n + 1];
dp[0][0] =0, dp[0][1] =0, dp[1][0] = 0;
for(int i = 0; i <= m; i ++){
for(int j = 0; j <= n; j ++){
if(i == 0 || j == 0){
dp[i][j] = 0;
continue;
}
dp[i][j] = 0;
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
// printf("%d ", dp[i][j]);
if(text1[i - 1] == text2[j - 1])dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
// printf("%d \n ", dp[i][j]);
}
}
return dp[m][n];
}
};
四、总结:
这篇文章将确定状态更加细化,我个人觉得是对学动态规划有所帮助,但毕竟知见障,我也不知道是否真的有帮助,兄弟们可以在评论区交流下。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情