递归实现
int lcs(char *T, char *P, int n, int m)
{
if (n < 1 || m < 1)
return 0;
else if (T[n] == T[m])
return lcs(T, P, n - 1, m - 1) + 1;
else
{
int left = lcs(T, P, n - 1, m);
int right = lcs(T, P, n, m - 1);
return left>right ? left : right;
}
}
动态规划(迭代版)
通过牺牲内存换取速度
// 返回长度值
int lcs2(char *T, char *P, int n, int m){
n++, m++;
int *array=new int[n*m]
for(int i=0;i<n;i++){
array[i*m]= 0;
}
for(int i=1;i<m;i++){
array[i]= 0;
}
for(int i=1; i<n-1;i++){
for(int j=1; j< m-1; j++){
if(T[i] == P[j]){
array[i*m+j] = array[(i-1)*m+j-1] + 1;
}
else{
int left = array[i*m+j-1];
int top = array[(i-1)*m+j];
array[i*m+j]=left > top? left:top;
}
}
}
int result = array[m*n-1];
char *output = new char[result];
//回溯输出子序列
backtrack(T, array, n, m, output, result);
//此处输出LCS的一种可能的结果
printf("%s", output);
delete[] output ;
delete[] array;
return result ;
}
回溯输出最长的公共子序列
void backtrack(char *T, int *array, int n, int m, char *output, int lcs_len){
for (int i = n - 1, j = m - 1; i>0 && j>0;){
if (array[i*m + j] == array[i*m + j -1]){
j--;
}
else if (array[i*m + j] == array[(i - 1)*m + j])
i--;
else{
output[--lcs_len] = T[i - 1];
i--, j--;
}
}
}
动态规划(节省内存版本)
如果只需要输出LCS的长度,不需要输出LCS可能的值,可以用空间压缩的方法将额外的空间减少为O{min(M,N)}
int lcs3(char * T, char *P, int n, int m)
{
n++;
int *listT = new int[n];//初始化一个列表
int *listP = new int[m*2];
for (int i = 0; i < n; i++)
{
listT[i] = 0;
}
for (int j = 0; j < m; j++)
{
listP[j] = 0;
}
int flag1 = 1;
int flag2 = 0;
for (int i = 0; i < n-1; i++){
for (int j = 0; j < m; j++){
if (T[i] == P[j]){
listP[flag1*m + j] = (j == 0 ? listT[i] + 1 : listP[flag2*m + j - 1] + 1);
}
else{
int left = j == 0 ? listT[i+1] : listP[flag1*m + j - 1];
listP[flag1*m + j] = left > listP[flag2*m + j] ? left : listP[flag2*m + j];
}
}
flag1 = flag2;
flag2 = -flag2 + 1;
}
int rerult = listP[flag2*m + m - 1];
delete[] listT;
delete[] listP;
return rerult;
}