最长公共子序列问题所谓,也即是分别给出长度为n和m的字符串A,B,然后找出其中最长公共子序列的最优值和最优解。
所谓最优值,也就是求出这个最长公共子序列的长度;而最优解,就是要求出这个最长最长公共子序列是什么的问题。给个不太恰当的例子:我们中学数学中经常会遇到求函数最值的问题,比如说求出函数 f(x) 的最大值,那么这个最大值就是最优值了;而最优解是什么呢?就是当f(x)取到最大值的时候的 x 值了。
解决的方法其实最简单的就是使用蛮力的方法,列举某一个字符串中的所有子序列,也就是求出这个字符串子序列的幂集;然后分别与另一字符串进行比较。那么由于幂集是 2 的 n 次方。所以其时间复杂度也就是 2 的 n 次方。
那么采用动态规划,可以通过寻求一个求最长公共子序列长度(下面简称LCS)的递推公式。
假设字符串 A = a1 a2 a3 a4.....ai B = b1 b2 b3 b4......bj
L[ i , j ]表示字符串A 和 B的最长公共子序列的长度。
那么:
稍作解释:①假如字符串A B中,有一个是长度为0;那么LCS = 0;
②假如,两个字符串的最后一个字符相同,那么其长度等于,A,B前面字符的匹配结果 +1
③假如,两个字符串的最后一个字符不相同,那么其长度等于,A减去最后一个字符和B进行匹配的结果,B减去最后一个字符和A进行匹配的结果,二者的最大值。
所以对于这个问题的求解,我们可以用一个二维表来进行计算求解,利用上面的公式逐行的填表。二维表的最后一个元素即是问题的最优值。
下面给出伪代码的实现:
#include<stdio.h> #include<string.h> int getMax(int a,int b) { return a>b?a:b; } char res[100]; //注意数组和字符串下标都是从0开始的 int LCS(char strA[],char strB[]) { int lenA = strlen(strA); int lenB = strlen(strB); printf("%d,%d",lenA,lenB); int n = lenA+1; int m = lenB+1; //创建一个二维数组 n 行 m 列 int result[n][m]; int i,j; for(i = 0; i < n; i++) result[i][0] = 0; //将第一列全部置零 for(j = 0; j < m; j++) result[0][j] = 0; //将第一行全部置零 int nn = 0; for(i = 1; i< n; i++) for(j = 1; j < m; j++) //逐行填充表格 { //如果两个字符相等,则result[i][j]等于表中左上角元素值+1 if(strA[i-1] == strB[j-1]) result[i][j] = result[i-1][j-1]+1; //如果两个字符不相等,则result[i][j]等于表中左边或者是上边元素值的最大者 //result[i][j-1]表示左边元素;result[j][i-1]表示s上边元素 else result[i][j] = getMax(result[i][j-1],result[i-1][j]); } int returnNum = result[n-1][m-1];//最后返回的结果:最长公共子序列长度 return returnNum; } int main() { char strA[100],strB[100]; printf("请输入第一个字符串:"); scanf("%s",strA); printf("请输入第二个字符串:"); scanf("%s",strB); int num = LCS(strA,strB); printf("最长公共子序列的长度是%d",num); }
http://blog.csdn.net/hackbuteer1/article/details/6686925
这个博客里面的第二种方法打印出公共自序列