最长公共子序列
给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共子序列,并返回其长度。
经典动态规划问题:
定义子问题dp[i ] [j ]为字符串A从第一个字符到第i个字符串和字符串B从第一个字符到第j个字符串的最长公共子序列,状态转移方程为:
- 假如A[i-1] = B[j-1] ,则dp[i ] [j] = dp[ i-1] [j-1]+1 (因为i-1和j-1位置的字符若相等,则在上一个状态直接加上最新的字符也是相等的)。
- 假如不相等,则取Math.max(dp[i] [j-1],dp[i-1] [j]),则取其中的较大者。
代码如下:
import java.util.*;
public class LCS {
public int findLCS(String A, int n, String B, int m) {
int[][] dp = new int[n+1][m+1];
for(int i = 0;i<=n;i++){
dp[i][0] = 0;
}
for(int i = 0;i<=m;i++){
dp[0][i] = 0;
}
char[] str1 = A.toCharArray();
char[] str2 = B.toCharArray();
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
if(str1[i-1]==str2[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[n][m];
}
}
最长公共子串
给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共子串,并返回其长度。
注意子串和子序列的区别,子序列和子串都是字符集合的子集,但是子序列不一定连续,但是子串一定是连续的。
此题也是使用DP,此处定义的 dp[i] [j] 为A中以i结尾的子串和B中以j结尾的子串的最大公共子串,此处的公共子串需要以A[m-1] 、B[n-1]结尾,即如果A[m-1] 、B[n-1]若不相等,则直接dp[i] [j] = 0;
状态转移方程:
- 若A[m-1] = B[n-1],则dp[i] [j] = dp[i-1] [j-1]+1;
- 若不相等,则 dp[i] [j] = 0;
代码如下:
import java.util.*;
public class LongestSubstring {
public int findLongest(String A, int n, String B, int m) {
int[][] dp = new int[n+1][m+1];
for(int i = 0;i<=n;i++){
dp[i][0] = 0;
}
for(int i = 0;i<=m;i++){
dp[0][i] = 0;
}
int max = 0;
for(int i = 1;i<=n;i++){
for(int j = 1;j<m;j++){
if(A.charAt(i-1)==(B.charAt(j-1))){
dp[i][j] = dp[i-1][j-1] + 1;
max = Math.max(max,dp[i][j]);
}
}
}
return max;
}
}