一、问题导入。
给定一个字符串S,从中删除一些字符后使剩下的串是一个回文串,最少需要删除几个字符才能使剩下的回文串最长。
例如:输入abcda,输出2; 输入google,输出2。
二、最长公共子序列与最长公共子串的区别。
1、最长公共子序列(Longest Common Subsequence,LCS)的定义:在字符串A和字符串B中都出现的序列,且顺序与母串保持一致最长的那个序列。
2、最长公共子串:相比LCS更加严格,序列必须连续出现,即公共的子字符串。
例如:csdnblog与belong,最长公共子序列为blog,最长公共子串为lo。
三、算法思想。
1、对于字符串A={A1,A2,A3...Am}和字符串B={B1,B2,B3...Bn},求其最长公共子序列。
定义C={C1,C2,C3...Ck}为字符串A和B的最长公共子序列LCS,用二维数组dp[i][j]记录{A1,A2...Ai}串和{B1,B2...Bj}串的LCS。
① 当i=0时,表示A串和B串的LCS为0,即dp[0][j]=0。
同理,当j=0时,A串的B串的LCS也为0,此时dp[i][0]=0。
② 若Am==Bn,则有Ck==Bn==Am,此时Ck-1是Am-1和Bn-1的LCS。
③ 若Am!=Bn,则Ck是Am-1和Bn的LCS,或Ck是Am和Bn-1的LCS。
综上,求解LCS的问题可以转化为递归求解其子问题。采用空间换时间的方法,用数组保存中间态,便于后面的计算。
用方程写出等式如下:
dp[i][j] = 0 ( i == 0 或 j == 0 )
dp[i][j] = dp[i-1][j-1]+1 ( i>0 , j>0且Ai == Bj )
dp[i][j] = max( dp[i][j-1] , dp[i-1][j] ) ( i>0 , j>0且Ai != Bj )
代码如下所示:
public class Main{
public static int getLCS(String A,String B) {
int m = A.length();
int n = B.length();
int dp[][] = new int[m+1][n+1];
for(int i=0;i<=m;i++) { // 考虑i为0或j为0的情况
for(int j=0;j<=n;j++) {
if(i==0 || j==0) {
dp[i][j] = 0;
}else if(A.charAt(i-1) == B.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
}else if(A.charAt(i-1) != B.charAt(j-1)) {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1 = sc.nextLine();
String str2 = new StringBuffer(str1).reverse().toString();
System.out.println(str1.length()-getLCS(str1,str2));
}
}
2、最长公共子串是最长公共子序列的特殊情况,此时序列连续。
用方程写出获取最长公共子串等式如下:
dp[i][j] = 0 ( i == 0 或 j == 0 )
dp[i][j] = dp[i-1][j-1]+1 ( i>0 , j>0且Ai == Bj )
dp[i][j] = 0 ( i>0 , j>0且Ai != Bj )
代码如下所示:
public class Main{
public static int getLCS(String A,String B) {
int m = A.length();
int n = B.length();
int dp[][] = new int[m+1][n+1];
int count = 0; // 记录最长公共子串的长度
for(int i=0;i<=m;i++) { // 考虑i为0或j为0的情况
for(int j=0;j<=n;j++) {
if(i==0 || j==0 || A.charAt(i-1) != B.charAt(j-1)) {
dp[i][j] = 0;
}else if(A.charAt(i-1) == B.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
count = Math.max(dp[i][j],count);
}
}
}
return count;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1 = sc.nextLine();
String str2 = new StringBuffer(str1).reverse().toString();
System.out.println(getLCS(str1,str2));
}
}