1、题目描述
2、解题思路
本题只能穷举所有情况,然后对比所有的公共子序列,找出最长的那个,计算长度。
因此,特别符合动态规划的条件,我们使用动态规划来求解。
假设我们已经知道最长公共子序列,为 lcs。
对两个字符串从右往左进行遍历检查字符属不属于 lcs:
1、如果 text1.charAt(i) == text2.charAt(j),则此时两个字符肯定属于 lcs ,于是 dp[i][j] = dp[i-1][j-1] + 1,意思是现在知道了长度至少是 1 了,真正的长度得取决于两个字符串再往左的部分。
2、如果 text1.charAt(i) != text2.charAt(j),则有三种情况:
2.1 text1.charAt(i) 属于 lcs,text2.charAt(j) 不属于,则 dp[i][j] = d[i][j-1],即结果取决于 text2 的前 j-1 的情况;
2.2 text1.charAt(i) 不属于 lcs,text2.charAt(j) 属于,则 dp[i][j] = d[i-1][j],即结果取决于 text1 的前 i-1 的情况;
2.3 两个字符都不属于 lcs,则 dp[i][j] = dp[i-1][j-1]
我们要找的是最长的公共子序列,于是选择上面三种情况最大的那个。
于是,dp[i][j] = Max(d[i][j-1], d[i-1][j], dp[i-1][j-1])
但是,对于两个字符都不属于的情况,会包含在 2.1 或 2.2 中,即 2.3 的值永远是最小的。
可以简化为:dp[i][j] = Max(d[i][j-1], d[i-1][j])
如果你不知道原理,也可以不简化,反正结果不变。
知道了状态转移方程,接下来就是确定 base_case 和遍历计算。
dp[i][0] == dp[0][j] == 0。即其中一个字符串长度为 0,则最长公共子序列不存在,长度为 0.
最后返回 dp[word1.length][word2.length]
3、解题代码
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int len1 = text1.length();
int len2 = text2.length();
int[][] dp = new int[len1 + 1][len2 + 1];
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[len1][len2];
}
}