5.最长公共子序列
最长公共子序列(LeetCode 1143题 难度:中等)
第一步:dp数组定义(字符串一般是二维)
dp[i][j]:表示S1[0,i]和S2[0,J]中最长的公共子序列的长度
S1="ace" S2="babcde"
比如dp[2][4]=2的含义,就是 S1="ac"和S2=“babc”,他们的最长公共子序列就是2,根据这个答案我们需要推出 dp[3][6];
第二步:定义 base case
专门让索引为0的行和列表示空串,dp[0][...]和dp[...][0]都初始化为 0,这就是base case (因为有一个字符串长度 是0)
第三步:状态转移方程
两种选择:
要么在LCS中,要么不在LCS中
怎么知道S[i]和S[j]到底在不在LCS中???
很容易想到,如果某个字符在LCS中,那么他必定在S1和S2中,因为LCS就是最长公共子序列
dp[i][j]表示s[0到i]和s2[0到j]中的最长递增子序列,这样就可以找到状态转移关系
如果S1[i]==S2[j],说明这个公共字符一定在lcs中,如果知道了s1[0...i-1]和s2[0...j-1]中lcs的长度,在+1 就是s1[0...i]和s2[0...j]中lcs的长度
根据dp定义得到以下逻辑
if(s1[i]==s2[j]){
//转为 子问题
dp[i][j]=dp[i-1][j-1]+1;
}
如果S1[i]!=S2[j],说明这两个字符至少有一个不在 lcs中,到底是哪个不在呢?
我们都试一下
比如 0-6, 那么下面的意思就是:1-6 和0-5哪个公共子序列长
if(s1[i]!=s2[j]){
//转为 子问题
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
明白了状态转移方程直接写出代码
public int longestCommonSubsequence(String text1, String text2) {
int m=text1.length();
int n=text2.length();
int[][] dp=new int[m+1][n+1];
char[] ch1 = text1.toCharArray();
char[] ch2 = text2.toCharArray();
for (int i = 1; i <= m; i++) {
for (int j = 1; j <=n ; j++) {
if(ch1[i-1]==ch2[j-1]){
dp[i][j]=dp[i-1][j-1]+1;
}else {
dp[i][j]=Math.max(dp[i][j-1],max(dp[i-1][j],dp[i-1][j-1]));
}
}
}
return dp[m][n];
}