动态规划的最长公共子序列算法的Java实现,代码中有详细的注释说明每一步的逻辑
public class LongestCommonSubsequence {
public static int[][] findLCS(char[] s1, char[] s2) {
// 初始化二维数组dp,dp[i][j]表示s1[0...i-1]和s2[0...j-1]的最长公共子序列的长度
int[][] dp = new int[s1.length+1][s2.length+1];
// 填充第一行和第一列为0,因为当一个字符串为空时,它们的最长公共子序列为0
for (int i = 0; i <= s1.length; i++) {
dp[i][0] = 0;
}
for (int j = 0; j <= s2.length; j++) {
dp[0][j] = 0;
}
// 动态规划填充dp数组
for (int i = 1; i <= s1.length; i++) {
for (int j = 1; j <= s2.length; j++) {
if (s1[i-1] == s2[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;
}
public static String getLCS(int[][] dp, char[] s1, char[] s2) {
int i = s1.length, j = s2.length;
StringBuilder sb = new StringBuilder();
// 从dp数组的右下角开始回溯
while (i > 0 && j > 0) {
if (s1[i-1] == s2[j-1]) {
// 如果s1[i-1]等于s2[j-1],那么这个字符一定属于最长公共子序列
sb.append(s1[i-1]);
i--;
j--;
} else {
// 否则,比较dp[i-1][j]和dp[i][j-1]的值,选择其中较大的那个方向回溯
if (dp[i-1][j] > dp[i][j-1]) {
i--;
} else {
j--;
}
}
}
// 最长公共子序列是逆序存储的,需要反转字符串
return sb.reverse().toString();
}
public static void main(String[] args) {
String s1 = "ABCD";
String s2 = "EACBFD";
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int[][] dp = findLCS(c1, c2);
String lcs = getLCS(dp, c1, c2);
System.out.println("最长公共子序列的长度为:" + dp[c1.length][c2.length]);
System.out.println("最长公共子序列为:" + lcs);
}
}