转自:http://blog.163.com/zhaohai_1988/blog/static/2095100852012792947765
最长公共子序列的意思就是寻找两个给定字符串的的子序列,该子序列在两个字符串中以相同的次序出现,但是不一定是连续的。(连续的那是子串)
例如序列X=ABCBDAB,Y=BDCABA。序列BCA是X和Y的一个公共子序列,但是不是X和Y的最长公共子序列,子序列BCBA是X和Y的一个LCS,序列BDAB也是。
思路:
最长公共子序列是动态规划(DP)的典型例子。
设X=<x1,x2,…,xm>和Y=<y1,y2,…,yn>为两个字符串,LCS(X,Y)表示X和Y的一个最长公共子序列,可以看出
- 如果xm=yn,则LCS ( X,Y ) = xm + LCS ( Xm-1,Yn-1 )。
- 如果xm!=yn,则LCS( X,Y )= max{ LCS ( Xm-1, Y ), LCS ( X, Yn-1 ) }
LCS问题也具有重叠子问题性质:为找出X和Y的一个LCS,可能需要找X和Yn-1的一个LCS以及Xm-1和Y的一个LCS。但这两个子问题都包含着找Xm-1和Yn-1的一个LCS,等等.
DP最终处理的还是数值(极值做最优解),找到了最优值,就找到了最优方案;为了找到最长的LCS,我们定义dp[i][j]记录序列LCS的长度,合法状态的初始值为当序列X的长度为0或Y的长度为0,公共子序列LCS长度为0,即dp[i][j]=0,所以用i和j分别表示序列X的长度和序列Y的长度,状态转移方程为
- dp[i][j] = 0 如果i=0或j=0
- dp[i][j] = dp[i-1][j-1] + 1 如果X[i-1] = Y[i-1] (X[i-1]就是X数组中的第i个)
- dp[i][j] = max{ dp[i-1][j], dp[i][j-1] } 如果X[i-1] != Y[i-1]
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
string strx,stry;
cin>>strx>>stry;
int nx = strx.length();
int ny = stry.length();
vector<vector<int>> vecall;
for (int i=0;i<=nx;i++)
{
vector<int> vec(ny+1,0);
vecall.push_back(vec);
}
for (int i=1;i<=nx;i++)
{
for (int j=1;j<=ny;j++)
{
if (strx[i-1]==stry[j-1])
{
vecall[i][j]=vecall[i-1][j-1]+1;
}
else if (vecall[i-1][j]>vecall[i][j-1])
{
vecall[i][j]=vecall[i-1][j];
}
else
{
vecall[i][j]=vecall[i][j-1];
}
}
}
int ans = vecall[nx][ny];//最长公共子序列长度
cout<<ans<<endl;
int i=nx;
int j=ny;
string lcs(ans,' ');
while (i && j)//找出最长公共子序列
{
if (strx[i-1]==stry[j-1] && vecall[i][j]==vecall[i-1][j-1]+1)
{
lcs[--ans]=strx[i-1];
i--,j--;
}
else if (vecall[i-1][j]>vecall[i][j-1])
{
i--;
}
else
{
j--;
}
}
for (i=0;i<lcs.length();i++)
{
cout<<lcs[i];//打印最长公共子序列
}
return 0;
}