最长公共子序列与最长公共子串【动态规划】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a515557595_xzb/article/details/88296989

一、问题导入。

给定一个字符串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));
    }
}

 

展开阅读全文

没有更多推荐了,返回首页