这是个很老的问题了,最近总是碰到,大三时候学的算法好多都忘记了,不如重新学一遍。
比起XXblog上的教程,我最喜欢的还是这个版本:http://www.ics.uci.edu/~eppstein/161/960229.html
里面的代码干净利落,解释也非常的清晰,一步一步怎么来的都很好。
这个问题是个动态规划的问题,最基本的样子是这样的:
假设当前搜索到字符串A,B中的字符a[i],b[j]. LCS[i,j]表示字串A,B分别在位置[i][j]及以后的最大子序列数量 IF A[i] == B[j]: LCS[i,j] = 1 + LCS[i+1][j+1] # 当前的算入,然后A,B再往后挪一格 ELSE LCS[i,j] = max(LCS[i][j+1], LCS[i+1][j]) # 分别挪动A,B后一格看看哪个好 ENDIF
由于这样递归能弄出的子问题里面,好多是重复的,因此我们可以像计算斐波那契数列那样,采用自底向上的方法,用非递归的方式实现。即从字符的末尾往前推导LCS[i][j],这样当计算LCS[i][j]的时候, LCS[i+1][j]或LCS[i][j+1]已经计算好了。
具体还是看英文教程吧,这里给出C++实现的代码。因为下午例会还得讲PPT,下面的代码用了全局变量传递计算好的序列,有点丑。
#include <iostream> using namespace std; /** * Longest Common Subsequence */ int** storeMat; int max(int x, int y){ return x>y? x:y; } int getLCSLength(char* A, char* B){ int sz_A = strlen(A); int sz_B = strlen(B); storeMat = new int*[sz_A+1]; for(int i=0; i<=sz_A; i++){ storeMat[i] = new int[sz_B+1]; // Allocate memory } for(int i=sz_A; i>=0; i--){ for(int j=sz_B; j>=0; j--){ if(A[i] == '\0' || B[j] == '\0'){ storeMat[i][j] = 0; } else if (A[i] == B[j]) { storeMat[i][j] = 1 + storeMat[1+i][1+j]; } else { storeMat[i][j] = max(storeMat[1+i][j], storeMat[i][1+j]); } } } return storeMat[0][0]; } string getLCS(char* A, char* B){ if(NULL == storeMat){ getLCSLength(A, B); } int i=0, j=0; string result; int sz_A = strlen(A); int sz_B = strlen(B); while(i < sz_A && j<sz_B){ if(A[i] == B[j]){ result += A[i]; i++; j++; } else if (storeMat[i+1][j] > storeMat[i][j+1]){ i++; } else { j++; } } return result; } int main() { char a[50], b[50]; scanf("%s %s", a, b); cout << getLCS(a, b); return 0; }