对于最长公共子序列(LCS),是典型的动态规划问题,对于这个问题,可以用如下思路来解答。
如:X{x1, x2, x3, ... },Y{y1, y2, y3, ...};
1.当x1 = y1时,则此时已找到一个相同的值,故接下来只需求{x2, x3, x4, ...}和{y2, y3, y4, ...}的LCS。
2.当x1 != y1时,则此时X和Y的LCS是下面两个LCS的最大值:
{x2, x3, x4, ...}和{y1, y2, y3, y4, ...}的LCS,
或者{x1, x2, x3, x4, ...}和{y2, y3, y4, ...}的LCS。
如:X{x1, x2, x3, ... },Y{y1, y2, y3, ...};
1.当x1 = y1时,则此时已找到一个相同的值,故接下来只需求{x2, x3, x4, ...}和{y2, y3, y4, ...}的LCS。
2.当x1 != y1时,则此时X和Y的LCS是下面两个LCS的最大值:
{x2, x3, x4, ...}和{y1, y2, y3, y4, ...}的LCS,
或者{x1, x2, x3, x4, ...}和{y2, y3, y4, ...}的LCS。
由上面可以看出这是一个递归问题。
即
即
_
| 0 i==0或j==0
|
c[i][j] = |- c[i-1][j-1] + 1 如果i,j>0和xi==yj
|
|_ max{c[i][j-1], c[i-1][j]} 如果i,j>0和xi != yj
| 0 i==0或j==0
|
c[i][j] = |- c[i-1][j-1] + 1 如果i,j>0和xi==yj
|
|_ max{c[i][j-1], c[i-1][j]} 如果i,j>0和xi != yj
其实通过代码中的嵌套for循环,即可知道每次通过比较来累积计算长度的。
#include <iostream> #include <cstring> using namespace std; char* LCS(const char* x, const char* y); int main() { char* x = "cbfgade"; char* y = "bcagfde"; char* s = LCS(x, y); cout<<"最长公共子序列为:"<<s<<endl; cout<<"长度为:"<<strlen(s)<<endl; return 0; } char* LCS(const char* x, const char* y) { int m = strlen(x); int n = strlen(y); int** c = new int*[m + 1]; for (int i = 0; i < m + 1; i++) { c[i] = new int[n + 1]; //每一行第一个元素初始化为0 c[i][0] = 0; } //第一行初始化为0 for (int i = 0; i < n + 1; i++) c[0][i] = 0; for (int i = 1; i < m + 1; i++) { for (int j = 1; j < n + 1; j++) { if (x[i - 1] == y[j - 1]) c[i][j] = c[i - 1][j - 1] + 1; else if (c[i][j - 1] >= c[i - 1][j]) c[i][j] = c[i][j - 1]; else c[i][j] = c[i - 1][j]; } } //c[m][n]值为最短子序列的长度 //用result来保存逆序LCS,通过c[m][n]的值与c[m - 1][ n - 1],c[m][n - 1],c[m - 1][n]来判断 int len = c[m][n]; char* result = new char[len + 1]; int count = len; while (m > 0 && n > 0) { if (c[m][n] == c[m - 1][ n - 1] + 1 && x[m - 1] == y[n - 1]) { result[--count] = x[m - 1]; m--; n--; } else if (c[m][n] == c[m][n - 1]) { n--; } else { m--; } } result[len] = '\0'; //释放内存 for (int i = 0; i < m + 1; i++) delete[] c[i]; delete []c; return result; }