牛客-NC92-最长公共子序列II
NC92. 最长公共子序列||(medium)
方法一:动态规划法
思路:这道题分两部分进行,首先是使用动态规划法求解LCS的长度,再逆序构建LCS。先说第一部分:定义一个二维dp数组 dp[i][j]:s1[0…i]和s2[0…j]为止的最长公共子序列的长度。
dp[0][0] = 0
dp[i][0] = 0
dp[0][j] = 0
dp[i][j] = dp[i - 1][j - 1] + 1, s1[i-1] == s2[j-1]
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]), s1[i-1] != s2[j-1]
可以写出以下代码:
public class NC92 {
/** * longest common subsequence * @param s1 string字符串 the string * @param s2 string字符串 the string * @return string字符串 */
public static String LCS (String s1, String s2) {
// write code here
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
int[][] dp = new int[str1.length + 1][str2.length + 1];
for(int i = 0; i <= str1.length; i++) {
for(int j = 0; j <= str2.length; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
continue;
}
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
if (str1[i - 1] == str2[j - 1]) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);
}
}
}
// 重构LCS
int num = dp[str1.length][str2.length];
//特判
if (num == 0) return "-1";
StringBuffer sb = new StringBuffer();
int l1 = str1.length;
int l2 = str2.length;
while (l1 > 0 && l2 > 0) {
if (s1.charAt(l1 - 1) == s2.charAt(l2 - 1)) {
sb.append(s1.charAt(l1 - 1));
l1 -= 1;
l2 -= 1;
} else {
if (dp[l1 - 1][l2] > dp[l1][l2 - 1]) {
// 走上边
l1 -= 1;
} else {
// 走左边
l2 -= 1;
}
}
}
return sb.reverse().toString();
}
public static void main(String[] args) {
String s1 = "1A2C3D4B56";
String s2 = "B1D23A456A";
System.out.println(LCS(s1, s2));
}
}
时间复杂度: O(MN),需要遍历s1和s2来填dp表。
空间复杂度: O(MN),额外的dp表的空间。
总结:只知道怎么求LCS的长度,不知道怎么重构LCS,对这道题还是没深入理解。