最长公共子序列(LCS)
注意最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence, LCS)的区别:子串(Substring)是串的一个连续的部分,子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列;更简略地说,前者(子串)的字符的位置必须连续,后者(子序列LCS)则不必。比如字符串acdfg同akdfc的最长公共子串为df,而他们的最长公共子序列是adf。LCS可以使用动态规划法解决。
学习了http://blog.csdn.net/v_july_v/article/details/6695482的思想,写了O(mn)的算法
#include <iostream> #include <algorithm> #include <string> #include <cstdio> #define N 105 using namespace std; int dp[N][N]; string s[2]; int s1,s2; int Max(int a,int b) { return a>b?a:b; } bool same(int i,int j) { if(s[0][i]==s[1][j]) return true; return false; } //如果需要输出基于最长公共字串的两串合并,参考hdu1503的AC代码 string solve()//输出最长公共字串 { s1=-1,s2=-1; for(int i=0; i<N; i++) for(int j=0; j<N; j++) dp[i][j]=0; for(int i=s[0].length()-1; i>=0; i--)//自上而下遍历,方便还原的时候顺序还原 for(int j=s[1].length()-1; j>=0; j--) { if(same(i,j)) { dp[i][j]=dp[i+1][j+1]+1; if(s1==-1) s1=i; s2=j;
} else dp[i][j]=Max(dp[i+1][j],dp[i][j+1]); } string ans=""; int i=0,j=0; while(i<s[0].length()&&j<s[1].length()) { if(same(i,j)) ans+=s[0][i],i++,j++; else { if(dp[i][j+1]>dp[i+1][j]) j++; else i++; } } return ans; } int main() { while(cin>>s[0]>>s[1]) { cout<<solve()<<endl; } return 0; }