问题
如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串。
注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,
则输出它们的长度4,并打印任意一个子串。
思想
求最长公共子串(Longest
Common Subsequence, LCS)是一道非常经典的动态规划题。
在开始想这道题之前应先理解什么是LCS(最长公共子串)。如串“abcbbc”,"abccbb",其中的一个字串"abc"是其公共子串,但不时最长公共字串。最长公共子串的定义中,并不要求最长公共子串必须连续出现在两个字符串中,只需要能保持顺序的出现在序列中即可。
在理解了什么是LCS之后,LCS的递归解就容易理解了:
c[i,j] =
0
(当 i=0或者j=0)
c[i-1,j-1] +1 (xi = yj,且 i>0,j>0)
Max(c[i,j-1], c[i-1,j]
) (xi!=yj , 且i, j >0 )
c[i,j]表示字符串 X[
1, i]和Y[1, j]的LCS长度。
算法导论给出了该算法。算法分成了两步。第一步找到LCS的长度。在找LCS长度的过程中,构造运算矩阵,以方便第二步求解LCS串。
扩展
LCS的定义不要求公共子串中的字符连续出现在两个字符串中。如果要求这样做。那么该怎么来做呢。
可以想到和LCS算法差不多的算法。即也维护一个M*N的矩阵c。如果a[i]==b[j],那么c[i][j]=c[i-1][j-1]+1;当i或者j等于0时,c[i][j]=1;如果不等c[i][j]=0。
代码实现参考代码2。
代码
package com.jy.string;
public class LCS {
public static void main(String[] args) {
char[] string = "abcbbc".toCharArray();
char[] string2 = "abccbb".toCharArray();
findLCS(string, string2);
}
/**
*
* @param string
* @param string2
*/
public static void findLCS(char[] string ,char[] string2) {
int m = string.length;
int n = string2.length;
int[][] c = new int[m+1][n+1];
int[][] b = new int[m+1][n+1];
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
if(string[i]==string2[j]) {
c[i+1][j+1]=c[i][j]+1;
b[i+1][j+1]= '\\';
} else {
if(c[i][j+1] >= c[i+1][j]) {
c[i+1][j+1] = c[i][j+1];
b[i+1][j+1]= '|';
} else {
c[i+1][j+1] = c[i+1][j];
b[i+1][j+1]= '-';
}
}
}
}
System.out.println("LCS长度:"+c[m][n]);
System.out.println("LCS序列:");
printLCS(b,string,m,n);
}
private static void printLCS(int[][] b, char[] string, int i, int j) {
if(i==0 || j==0) {
return ;
}
if(b[i][j]=='\\') {
printLCS(b, string, i-1, j-1);
System.out.println(string[i-1]);
} else if(b[i][j]=='|'){
printLCS(b, string, i-1, j);
} else {
printLCS(b, string, i, j-1);
}
}
}
package com.jy.string;
public class LCS2 {
public static void main(String[] args) {
findLCS("abcdefg".toCharArray(), "abcdged".toCharArray());
}
public static void findLCS(char[] string1, char[] string2) {
int m = string1.length;
int n = string2.length;
int[][] c = new int[m][n];
int max=0;
int maxPosX = 0;
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
if(string1[i]==string2[j]) {
if(i==0||j==0) {
c[i][j] = 1;
} else {
c[i][j] = c[i-1][j-1]+1;
}
if(c[i][j]>max) {
max =c[i][j];
maxPosX = i;
}
} else {
c[i][j] = 0;
}
}
}
System.out.println(max);
for(int i = maxPosX-max+1;i<=maxPosX;i++) {
System.out.print(string1[i]);
}
}
}
分享到:
相关推荐
算法题目:最长公共子序列(Longest Common Subsequence, LCS) 题目描述: 给定两个字符串 text1 和 text2,找到这两个字符串的最长公共子序列(LCS)的长度。一个字符串的子序列是指这样一个字符串:它通过删除原...
它与经典的最长公共子序列问题(LCS,Longest Common Subsequence)类似,但有其特定的要求:不仅要求子序列在原序列中存在,还要求这个子序列是递增的。 一、最长公共子序列问题(LCS) 在两个给定的序列中,最长...
最长公共子序列(LCS,Longest Common Subsequence)是计算机科学中,特别是算法和信息学竞赛中的一个重要概念。在两个或多个字符串中,LCS是指没有改变原有顺序的最长得相同子串。这个概念在文本比较、生物信息学、...
- 最长公共子序列(Longest Common Subsequence, LCS)。 - 动态规划的设计与优化,以及对特殊情况的处理。 3. **回溯算法(Backtracking)** - 回溯算法解题套路和框架。 - 如何使用回溯算法解决问题,例如...
最长公共子序列(Longest Common Subsequence, LCS)是一个经典的计算机科学问题,主要涉及字符串处理和动态规划。问题的核心在于找到两个或多个字符串之间共享的最长的子序列,这个子序列不必连续,但必须保持原有...
- **字符串的LCS(Longest Common Subsequence)**:计算两个字符串的最长公共子序列。 附件中的"附件2---题目"很可能包含了基于后缀数组的各种实践题目,这些题目可以帮助学习者巩固理论知识并提高实际编程能力。...
- **最长公共子序列(LCS - Longest Common Subsequence)**:找出两个或多个序列中最长的相同子序列。通过构建一个二维DP表格来解决。 #### 贪心算法 贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择...