题目
动态规划 LCS算法
public int longestCommonSubsequence(String text1, String text2) {
// 在头部多增加一行一列, 就不用考虑边界条件了, 因为是当前值是和以前的值有关
int [][] dp = new int[text1.length() + 1][text2.length() + 1];
for (int i = 1; i < text1.length() + 1; i ++) {
for (int j = 1; j < text2.length() + 1; 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[text1.length()][text2.length()];
}
思路
(1) 两个字符串A和B, 长度可能不相等, 如果两个字符串最后一位不相同, 那么肯定有一个字符串的最后一位是没用的.或者两个都没用.
(2) 去掉A的, 看A和B的情况
(3) 去掉B的, 看A和B的情况
(4) 两个都去掉, 看A和B的情况
(5) 如果最后一个字符相等的话, 那么表明这两个字符一定是可以用上的(因为是子序列, 任何两个相等的字符都可以被用上, 只要不重复用某一个字符串的元素就行)
(6) 那就表明这两个字符串都可以去掉, 看A和B的情况 + 1即可
(7) 那么问题就是, 什么时候应该去掉A的, 什么时候去掉B的, 什么时候去掉A, B的?
(8) 那么我们是不是可以不管到底去掉哪个是对的, 我们随便去, 然后看去掉之后, 是怎么影响结果的, 我们保留结果最大的一种方案是不是就可以了.
(9) 用一个二元数组dp[i][j] 表示长度为i的字符串A, 和长度为j的字符串B, 他们的公共子序列的最大长度
(10) 无脑去掉A的最后, 就是dp[i - 1][j], 无脑去掉B的最后, 就是dp[i][j - 1], 无脑去掉A, B的最后, 就是dp[i - 1][j - 1].
(11) dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) 当两个字符串最后一位不相等时, 这是必然的结果
(12) 如果按11计算 那么dp[i - 1][j - 1]其实可以不考虑了, 因为dp[i - 1][j]和dp[i][j - 1]在计算的时候, 已经考虑到dp[i - 1][j - 1]了, 所以dp[i - 1][j - 1]的存在不会改变结果
(13) 当两个字符串相等时, dp[i][j] = dp[i - 1][j - 1] + 1;
(14) 这样就可以从头开始计算, 逐渐计算到i = 真正A的长度, j = 真正B的长度