思路:动态规划
所谓子序列,就是要保留原始顺序,但可以是不连续的。审题之后你可能会有疑问,这个问题为啥就是动态规划来解决呢?因为子序列类型的问题,穷举出所有可能的结果都不容易,而动态规划算法做的就是穷举 + 剪枝,它俩天生一对儿。所以可以说只要涉及子序列问题,十有八九都需要动态规划来解决。
dp[i][j]的意思:dp[i][j]表示以str1(i-1)为结尾的s1的子序列 和 以str2(j-1) 为结尾的s2的子序列的公共子序列的最长长度- 如果
s1[i] = s2[j] - 如果
s1[i] != s2[j],需要继承下来之前的长度,max一下。 - 最后返回数组最后一个元素即可,因为即使两个单词的最后一个字符不相同,他们还是会继承之前的更短的序列的最大长度,比如abcdex abcdek还是会返回3,这就是子序列的特点。
为了保证第一行和第一列的元素可以取到dp[i - 1][j - 1],在他们前面填充0
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m + 1][n + 1];//为了最左和顶部多出一行0,这里声明。
//注意ij的取值范围
for (int i = 1; i < m + 1; i++) {
for (int j = 1; j < n + 1; j++) {
//填充0,声明数组默认就全填0
if (text1.charAt(i - 1) == text2.charAt(j - 1)) {//如果两个char相等,则在s1、s2都去掉char的情况上+1
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);//不相等,看s1去掉char大还是s2去掉char大
}
}
}
return dp[m][n];
}
}
// 获取子序列
public String getPath(int[][] dp, String text1, String text2) {
StringBuffer sb = new StringBuffer();
int i = dp.length - 1, j = dp[0].length - 1;
while (i >= 1 && j >= 1) {
if (dp[i][j] == dp[i - 1][j - 1] + 1) { //char1 = char2
sb.append(text1.charAt(i - 1));
i--;
j--;
} else if (dp[i][j] == dp[i - 1][j]) {//char1 != char2
i--;
} else if (dp[i][j] == dp[i][j - 1]) {//char1 != char2
j--;
}
}
return sb.reverse().toString();
}