最长公共子序列问题文档格式.docx
- 文档编号:13743340
- 上传时间:2022-10-13
- 格式:DOCX
- 页数:9
- 大小:243.10KB
最长公共子序列问题文档格式.docx
《最长公共子序列问题文档格式.docx》由会员分享,可在线阅读,更多相关《最长公共子序列问题文档格式.docx(9页珍藏版)》请在冰豆网上搜索。
INTHEBEGINNING
S2:
ALLTHINGSARELOST
则S1和S2的一个最长公共子序列为THING。
又比如:
ABCBDAB
S2:
BDCABA
则它们的一个最长公共子序列为BCBA。
这里需要注意的是,一个子序列不一定必须是连续的,即中间可被其他字符分开,单它们的顺序必须是正确的。
另外,最长公共子序列不一定只有一个,而我们需要寻找的是其中一个。
当然,如果要求子序列里面的元素必须连成一片也是可以的。
实际上,连成一片的版本比这里实现的更容易。
4.过程
我们可以通过蛮力策略解决这个问题,步骤如下:
1.检查S1[1..m]里面每一个子序列。
2.看看其是否也是S2[1..n]里的子序列。
3.在每一步记录当前找到的子序列里面最长的子序列。
这种方法的效率十分低下。
因此本实验采用动态规划的方法实现该算法。
利用动态规划寻找最长公共子序列步骤如下:
1.寻找最长公共子序列的长度。
2.扩展寻找长度的算法来获取最长公共子序列。
策略:
考虑序列S1和S2的前缀序列。
设c[i,j]=|LCS(S1[1..i],S2[1..j])|,则有c[m,n]=|LCS(S1,S2)|
所以有
c[i–1,j–1]+1,如要S1[i]=S2[j]
c[i,j]=
max{c[i-1,j],c[i,j-1]},如果S1[i]≠S2[j]
然后回溯输出最长公共子序列过程:
5.实现源代码
packagelcsimple;
publicclassLCSImplem{
//返回一个决定搜索方向的数组
privatestaticint[][]getLength(char[]stringArr1,char[]stringArr12){
int[][]b=newint[stringArr1.length][stringArr12.length];
int[][]c=newint[stringArr1.length][stringArr12.length];
for(inti=1;
i<
stringArr1.length;
i++){
for(intj=1;
j<
stringArr12.length;
j++){
//S1[i]=S2[j]的情况
if(stringArr1[i]==stringArr12[j]){
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
//S1[i]≠S2[j]的情况
elseif(c[i-1][j]>
=c[i][j-1]){
c[i][j]=c[i-1][j];
b[i][j]=0;
else{
c[i][j]=c[i][j-1];
b[i][j]=-1;
}
}
returnb;
}
//回溯的实现,采用递归法
privatestaticvoidDisplay(int[][]b,char[]stringArr1,inti,intj){
if(i==0||j==0)
return;
if(b[i][j]==1){
Display(b,stringArr1,i-1,j-1);
System.out.print(stringArr1[i]+"
"
);
elseif(b[i][j]==0){
Display(b,stringArr1,i-1,j);
elseif(b[i][j]==-1){
Display(b,stringArr1,i,j-1);
publicstaticvoidmain(String[]args){
Stringstr1="
ABCBDAB"
;
Stringstr2="
BDCABA"
str1="
+str1;
str2="
+str2;
char[]stringArr1=str1.toCharArray();
char[]stringArr2=str2.toCharArray();
int[][]b=getLength(stringArr1,stringArr2);
Display(b,stringArr1,stringArr1.length-1,stringArr2.length-1);
}
6.断点调试及代码分析
首先在main方法里定义两个字符串,如:
对这两个字符串,使它们的第一个字符为空,即初始化之后的c[][]的第一行第一列,之所以要空出,是因为c[][]代表的是两个字符串数组多少个,0的意思就是某个字符串的长度为0。
然后将这两个字符串分割为char型数组:
接下来就调用getLength方法计算出决定搜索方向的数组,传到该方法的两个数组参数stringArr1和stringArr2的值可以看到
然后定义两个二维数组b[][],c[][],大小为stringArr1.length*stringArr12.length,用于接受结果矩阵。
接着遍历每一个stringArr1的值,与stringArr2的每一个值做比较:
循环的第一层判断,就是当当前字符匹配的时候,c[i][j]最为前缀序列为后面的匹配计算使用,将当前值赋值为1,b[i][j]用于保存匹配结果记为1:
把下面的两个判断作为第二层判断,即当当前字符不匹配的时候对c[i][j]做计算,c[i][j]就是该值在矩阵中上面一个数和左边一个数中较大的值:
这些判断就是对该矩阵值的计算,c矩阵:
但是这个方法返回的是b矩阵,b矩阵在当前位置在字符匹配时的值为1,不匹配时,就对c矩阵做出比较,该值在矩阵中左边的数值大于上边的数值时,b矩阵在当前位置在字符匹配时的值为0,反之记为-1。
因此,计算返回b矩阵,输出b矩阵
得到:
最后就是对结果的输出,对b矩阵调用Display方法:
当当前值为1时,说明字符匹配成功,再对左上方的值进行比较;
当当前值为0时,说明左边的值大于上边的值,采用递归法,再对上边的值进行比较;
当当前值为-1时,对左边的值进行比较。
下面是对b的迭代:
这个方法,就是对下面矩阵方向的计算:
最后输出判断中匹配上的结果。
7.算法分析
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m*n)次就会遇到i=0或j=0的情况,此时开始返回。
返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m*n)。
8.实验结果
在main方法中输入的字符串为:
所以得到结果:
改变输入的字符串测试:
结果准确,实验结束。
9.实验总结
对最长公共子序列的求解,实际上是对动态规划思想的学习,这个实验实现的算法比前两个实验实现的算法难度又有所提升,对字符串进行反复递归时容易出错,所以只能先对简单的字符串计算进行测试。
个人认为,动态规划思想中难的部分就是突出在反复的循环/递归,对循环参数的取值往往让人伤神,需要十分谨慎小心,并反复的测验才能确保算法的正确性。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最长 公共 序列 问题