「java求最长公共子序列」java实现最长公共子序列

博主:adminadmin 2023-03-19 08:42:09 613

今天给各位分享java求最长公共子序列的知识,其中也会对java实现最长公共子序列进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

求最长公共子序列(动态规划)

// 求LCS的长度

class LCS

{

public:

LCS(int nx, int ny, char *x, char*y); //创建二维数组c、s和一维数组a、b,并进行初始化

void LCSLength(); //求最优解值(最长公共子序列长度)

void CLCS(); //构造最优解(最长公共子序列)

……

private:

void CLCS(int i, int j);

int **c, **s.m, n;

char *a, *b;

};

int LCS::LCSLength()

{

for(int i=1; i=m; i++) c[i][0]=0;

for(i=1; i=n; i++) c[0][i]=0;

for (i=1; i=m; i++)

for (int j=1; j=n; j++)

if (x[i]==y[j]){

c[i][j]=c[i-1][j-1]+1; s[i][j]=1; //由c[i-1][j-1]计算c[i][j]

}

else if (c[i-1][j]=c[i][j-1]){

c[i][j]=c[i-1][j]; s[i][j]=2; //由c[i-1][j]得到c[i][j]

}

else {

c[i][j]=c[i][j-1]; s[i][j]=3; //由c[i][j-1]得到c[i][j]

}

return c[m][n]; //返回最优解值

}

// 构造最长公共子序列

void LCS::CLCS(int i, int j)

{

if (i==0||j==0) return;

if (s[i][j]==1){

CLCS(i-1, j-1);

couta[i];

}

else if (s[i][j]==2) CLCS(i-1, j);

else CLCS(i, j-1);

}

java怎么写求最长的公共子序列

/*目标:输出两个字符串的所有公共最长子序列date:09-11-26BY:zggxjxcgx算法:判断较短串是否为较长串的子序列,如果是则得到结果;否则,对较短串进行逐个字符删除操作(将字符替换为'#'表示删除)。删除操作用递归函数进行实现。每层递归删除一个字符,若删除一个字符后未得到匹配子序列,则还原该字符所在位置。第n层递归未找到匹配子序列,则将递归层数加1,重复删除直到剩下空串。*/#include#includeintdep=0;/*较短串的长度*/intdepflag=0;/*下一步要探测的深度*/intlastflag=0;/*是否找到匹配子序列,1为找到*/intcount=0;/*目标结果的个数*/intmystrcmp(char*s1,char*s2)/*判断s2是否为s1的子串*/{while(*s1*s2)if(*s2=='#')s2++;elseif(*s2==*s1){s1++;s2++;}elses1++;while(*s2=='#')s2++;if(*s2=='\0')return1;return0;}voidpristr(char*str)/*打印最长子序列*/{if(0==count++)printf("\n公共最长子序列:\n");printf("%2d:",count);while(*str){if(*str!='#')printf("%c",*str);str++;}printf("\n");}/*递归函数求最长子序列。start控制下一个要检测的字符,deptemp控制递归的深度,first为's'表示第一层递归*/intfun(char*str1,char*str2,char*start,intdeptemp,charfirst){inti=0,j=0;char*s,cback;do{s=start;if('s'==first)deptemp=depflag;/*在第一层设置递归深度*/while(*s){if(*s=='#'){s++;continue;}cback=*s;*s='#';/*删除当前字符*/if(mystrcmp(str1,str2)){pristr(str2);lastflag=1;}/*找到匹配,将lastflag设为1,在完成深度为deptemp+1的探测(找到所有匹配)后退出递归*/elseif(deptemp0)fun(str1,str2,s+1,deptemp-1,'n');/*深度探测,s+1表示从下一个位置开始删除*/*s=cback;s++;/*还原该位置的字符,以便下次进行探测*/}if('s'==first)++depflag;/*删除depflag+1个字符还未找到,则递归深度加1*/}while(depflagstrlen(st2))s1=st1,s2=st2;/*将s1设为较长的串*/elses1=st2,s2=st1;printf("\nstr1:%s\nstr2:%s\n",s1,s2);dep=strlen(s2);/*得到较短串的长度*/if(mystrcmp(s1,s2))pristr(s2);elseif(0==fun(s1,s2,s2,0,'s'))printf("\n没有公共元素!\n");//printf("%d\n",mystrcmp("afdebjewcwedw","abcdw#"));}

java求最大公共子串

二楼改的

c = b.substring(i,j-1);

之后下标越界没了。

程序无法出结果,中间有死循环。当while语句执行完之后j是a.length();然后是执行内循环for语句for(j=b.length()-1;j0;j--) 此时只比较J0;。。。。好像是个死循环。最内层的循环可以在加一个int k来控制。多次运行导致cpu上升至100%的。

提供一种矩阵算法,这是LCS的一种算法:

public class stringCompare {

/**求最长匹配子字符串算法

str数组记录每行生成的最大值strmax

max数组记录str数组最大时所处的列号nummaxj

最大子字符串为substring(nummax-strmax+1,strmax+1)

*/

public static void main(String[] args) {

String s1="asdfgxxcvasdfgc";

String s2="asdfxxcv";

int m=s1.length();

int n=s2.length();

int k=0;

int nummax=0;

int []str=new int[m];

int []max=new int[m];

int []num=new int[m];

for(int i=0;im;i++) //生成矩阵数组

for(int j=n-1;j=0;j--)

{

if(s1.charAt(i)==s2.charAt(j))

if(i==0||j==0)

{

num[j]=1;

max[i]=j;

str[i]=1;

}

else

{

num[j]=num[j-1]+1;

if(max[i]num[j])

{

max[i]=j;

str[i]=num[j];

}

}

else

num[j]=0;

}

for(k=0;km;k++) //求str数组的最大值

{

if(nummaxstr[k])

{

nummax=str[k];

}

}

for(k=0;km;k++)

if(nummax==str[k])

System.out.println(s2.substring(max[k]-str[k]+1,max[k]+1));

}

}

寻找字符串数组的最长公共子串

所谓最长公共子串问题是寻找两个或多个已知字符串最长的子串。例如字符串 “ABCD”与“ABCDE”、“FABCDE”的最长公共子串是“ABCD”……

值得注意的是,有些人把最长公共子序列、最长公共前缀与最长公共子串搞混淆了,请特别注意⚠️。

《高效算法:竞赛、应试与提高必修128例》中介绍了最长公共子串的算法,不过只是找两个字符串之间的最长公共子串, 并没有给出任意个数 (此处当然指的是3个或以上)字符串的最长公共子串的求法。

现在用Python试写如下:

最长子串还可以用lamada写法,看起来更加简洁

这个方法的复杂度是 O(n1 x n1 x (n1 + ... + nK)) , 如果字符串不复杂,还是可以一用的😄。

动态规划 最长公共子序列 过程图解

首先需要科普一下,最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。

这里给出一个例子:有两个母串

cnblogs

belong

比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与母串保持一致,我们将其称为公共子序列。最长公共子序列(Longest Common Subsequence,LCS),顾名思义,是指在所有的子序列中最长的那一个。

子串是要求更严格的一种子序列, 要求在母串中连续地出现 。

在上述例子的中,最长公共子序列为blog(cnblogs,belong),最长公共子串为lo(cnblogs, belong)。

给一个图再解释一下:

如上图,给定的字符序列: {a,b,c,d,e,f,g,h},它的子序列示例: {a,c,e,f} 即元素b,d,g,h被去掉后,保持原有的元素序列所得到的结果就是子序列。同理,{a,h},{c,d,e}等都是它的子序列。

它的子串示例:{c,d,e,f} 即连续元素c,d,e,f组成的串是给定序列的子串。同理,{a,b,c,d},{g,h}等都是它的子串。

这个问题说明白后,最长公共子序列(以下都简称LCS)就很好理解了。

给定序列s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2},s1和s2的相同子序列,且该子序列的长度最长,即是LCS。

s1和s2的其中一个最长公共子序列是 {3,4,6,7,8}

求解LCS问题,不能使用暴力搜索方法。 一个长度为n的序列拥有 2的n次方个子序列,它的时间复杂度是指数阶 ,太恐怖了。解决LCS问题,需要借助动态规划的思想。

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。 为了避免大量的重复计算,节省时间,我们引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法。

解决LCS问题,需要把原问题分解成若干个子问题,所以需要刻画LCS的特征。

设A=“a0,a1,…,am”,B=“b0,b1,…,bn”,且Z=“z0,z1,…,zk”为它们的最长公共子序列。不难证明有以下性质:

如果am=bn,则zk=am=bn,且“z0,z1,…,z(k-1)”是“a0,a1,…,a(m-1)”和“b0,b1,…,b(n-1)”的一个最长公共子序列;

如果am!=bn,则若zk!=am,蕴涵“z0,z1,…,zk”是“a0,a1,…,a(m-1)”和“b0,b1,…,bn”的一个最长公共子序列;

如果am!=bn,则若zk!=bn,蕴涵“z0,z1,…,zk”是“a0,a1,…,am”和“b0,b1,…,b(n-1)”的一个最长公共子序列。

有些同学,一看性质就容易晕菜,所以我给出一个图来让这些同学理解一下:

以我在第1小节举的例子(S1={1,3,4,5,6,7,7,8}和S2={3,5,7,4,8,6,7,8,2}),并结合上图来说:

假如S1的最后一个元素 与 S2的最后一个元素相等,那么S1和S2的LCS就等于 {S1减去最后一个元素} 与 {S2减去最后一个元素} 的 LCS 再加上 S1和S2相等的最后一个元素。

假如S1的最后一个元素 与 S2的最后一个元素不等(本例子就是属于这种情况),那么S1和S2的LCS就等于 : {S1减去最后一个元素} 与 S2 的LCS, {S2减去最后一个元素} 与 S1 的LCS 中的最大的那个序列。

假设Z=z1,z2,⋯,zk是X与Y的LCS, 我们观察到

如果Xm=Yn,则Zk=Xm=Yn,有Zk−1是Xm−1与Yn−1的LCS;

如果Xm≠Yn,则Zk是Xm与Yn−1的LCS,或者是Xm−1与Yn的LCS。

因此,求解LCS的问题则变成递归求解的两个子问题。但是,上述的递归求解的办法中, 重复的子问题多,效率低下。改进的办法——用空间换时间,用数组保存中间状态,方便后面的计算。这就是动态规划(DP)的核心思想了。

DP求解LCS

用二维数组c[i][j]记录串x1x2⋯xi与y1y2⋯yj的LCS长度,则可得到状态转移方程

以s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2}为例。我们借用《算法导论》中的推导图:

图中的空白格子需要填上相应的数字(这个数字就是c[i,j]的定义,记录的LCS的长度值)。填的规则依据递归公式,简单来说:如果横竖(i,j)对应的两个元素相等,该格子的值 = c[i-1,j-1] + 1。如果不等,取c[i-1,j] 和 c[i,j-1]的最大值。首先初始化该表:

S1的元素3 与 S2的元素5 不等,c[2,2] =max(c[1,2],c[2,1]),图中c[1,2] 和 c[2,1] 背景色为浅黄色。

继续填充:

至此,该表填完。根据性质,c[8,9] = S1 和 S2 的 LCS的长度,即为5。

本文S1和S2的最LCS并不是只有1个,本文并不是着重讲输出两个序列的所有LCS,只是介绍如何通过上表,输出其中一个LCS。

我们根据递归公式构建了上表,我们将从最后一个元素c[8][9]倒推出S1和S2的LCS。

c[8][9] = 5,且S1[8] != S2[9],所以倒推回去,c[8][9]的值来源于c[8][8]的值(因为c[8][8] c[7][9])。

c[8][8] = 5, 且S1[8] = S2[8], 所以倒推回去,c[8][8]的值来源于 c[7][7]。

以此类推,如果遇到S1[i] != S2[j] ,且c[i-1][j] = c[i][j-1] 这种存在分支的情况,这里请都选择一个方向(之后遇到这样的情况,也选择相同的方向)。

这就是倒推回去的路径,棕色方格为相等元素,即LCS = {3,4,6,7,8},这是其中一个结果。

如果如果遇到S1[i] != S2[j] ,且c[i-1][j] = c[i][j-1] 这种存在分支的情况,选择另一个方向,会得到另一个结果。

即LCS ={3,5,7,7,8}。

构建c[i][j]表需要Θ(mn),输出1个LCS的序列需要Θ(m+n)。

参考:

关于java求最长公共子序列和java实现最长公共子序列的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。