最长子序列问题分析及求解实例
最长子序列问题(Longest Common Subsequence),即求解两序列的最长子序列或其长度。
EX:有两序列
A:LolitaIsHisSin
B:LolitaIsHisLight
显而易见,“LolitaIsHis”即是A和B的最长子序列,其长度为11.
求解最长公共子序列长度 LongestLength 这样的问题,我们有以下思路:
1、从头开始比对,遇到相同项即让记录的最大长度加1
2、若两项不相同,则看序列中的下一项
3、如此比对直到比对完两个序列中所有的项
上代码
—LCM迭代法实现 —
/* Find the Length of Longest Common Subsequence -- sotre res in note */
/* note is used to store the length */
void LCM(string stringA,string stringB,int note[sizex][sizex])
{
for(int ptrA =0;ptrA<=stringA.length();ptrA++){
for(int ptrB = 0;ptrB<=stringB.length();ptrB++){
if(ptrA==0||ptrB==0)
note[ptrA][ptrB]= 0;
else if(stringA[ptrA] == stringB[ptrB] ){
/* Longest Length Add 1 */
note[ptrA][ptrB]= note[ptrA-1][ptrB-1]+1;
}else {
/* choose the bigger in upwards and left -- using ?-expression */
note[ptrA][ptrB] = note[ptrA-1][ptrB]>note[ptrA][ptrB-1]
?
note[ptrA-1][ptrB]:note[ptrA][ptrB-1];
}
}
}
/* show the result */
DisPlayArray(note);
}
—LCM迭代法实现 —
调用函数DisPlayArray();
/* DisPlay The result Array */
void DisPlayArray(int note[sizex][sizex])
{
for(int ptra = 0;ptra<sizex;ptra++)
for(int ptrb = 0;ptrb<sizex;ptrb++){
if(ptrb == sizex-1)
/* end of the line: note[num][end] --> '\n' */
cout<<endl;
else
cout<<note[ptra][ptrb]<<" ";
}
}
主函数
int main()
{
int note[sizex][sizex] = {0};
/* compare the two str -- "1234FIRST5678" and "1234SECOND5678" */
LCM("1234FIRST5678","1234SECOND5678",note);
return 0;
}
执行结果
可以看到,从第一项比较到最后一项得出的最大子序列长度为9 —— 12345678和S,符合预期。
值得注意的是,第二步引发了一个问题,让我们不倾向于选择使用递归的方法求解这个问题:
对于序列
C: didactical
D: advantage
比对到第三项时,我们可以选择先看C的下一项,或者D的下一项.
而两种选择都引发了后续的类似的问题---都会引发先看哪一个序列的问题
事实上,问题并不在于先看哪一个序列,因为两个序列的所有项都会被逐一比较。问题在于每次选择都引发了后续的类似选择,导致有些比较的情况被重复进行,浪费了时间。
用一张图来看看上面所说的“重复”出现在哪儿:
可以看到,不同的选择可能会引发相同的比较情况,故而使用递归的方法求解这个问题是不够理想的。