最长公共子序列(LCS)问题
Posted home普通的人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长公共子序列(LCS)问题相关的知识,希望对你有一定的参考价值。
最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列;也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续。
1、序列str1和序列str2
·长度分别为m和n;
·创建1个二维数组L[m.n];
·初始化L数组内容为0
·m和n分别从0开始,m++,n++循环:
- 如果str1[m] == str2[n],则L[m,n] = L[m - 1, n -1] + 1;
- 如果str1[m] != str2[n],则L[m,n] = max{L[m,n - 1],L[m - 1, n]}
·最后从L[m,n]中的数字一定是最大的,且这个数字就是最长公共子序列的长度
·从数组L中找出一个最长的公共子序列
2、从数组L中查找一个最长的公共子序列
i和j分别从m,n开始,递减循环直到i = 0,j = 0。其中,m和n分别为两个串的长度。
·如果str1[i] == str2[j],则将str[i]字符插入到子序列内,i--,j--;
·如果str1[i] != str[j],则比较L[i,j-1]与L[i-1,j],L[i,j-1]大,则j--,否则i--;(如果相等,则任选一个)
我们可以得到其中公共子串:B C B A 和 B D A B。
#include <iostream> #define N 1000 using namespace std; //c[i][j]存储str1[1...i]与str2[1...j]的最长公共子序列的长度 int c[N][N]; //flag[i][j]标记是那种子问题 //flag[i][j]==0为str1[i]==str2[j] //flag[i][j]==1为c[i-1][j]>=s[i][j-1] //flag[i][j]==-1为c[i-1][j]<s[i][j-1] int flag[N][N]; int getLCSlength(string str1, string str2) { int len1 = str1.size(); int len2 = str2.size(); for (int i = 0; i <= len1; i++) { for (int j = 0; j <= len2; j++) { if (i == 0 || j == 0) c[i][j] = 0; else if (str1[i - 1] == str2[j - 1]) { c[i][j] = c[i - 1][j - 1] + 1; flag[i][j] = 0; } else if (c[i - 1][j] >= c[i][j - 1]){ c[i][j] = c[i - 1][j]; flag[i][j] = 1; } else{ c[i][j] = c[i][j - 1]; flag[i][j] = -1; } } } return c[len1][len2]; } void getLCS(string s1, string s2,int len,char *lcs) { int i = s1.size(); int j = s2.size(); while(i&&j) { if(flag[i][j]==0) { lcs[--len] = s1[i-1]; i--; j--; } else if(flag[i][j]==1) //往上 i--; else if(flag[i][j]==-1)//往左 j--; } } int main() { string str1,str2,lcs; char lcs[N]; cout<<"请输入字符串1:"<<endl; cin>>str1; cout<<"请输入字符串2:"<<endl; cin>>str2; int lcsLen = getLCSlength(str1,str2); cout<<"最长公共子序列长度:"<<lcsLen<<endl; getLCS(str1,str2,lcsLen,lcs); cout<<"最长公共子序列为:"; for(int i=0;i<lcsLen;i++) cout<<lcs[i]; return 0; }
以上是关于最长公共子序列(LCS)问题的主要内容,如果未能解决你的问题,请参考以下文章