什么是最大公共子序列?
子序列为父序列的0~n个子集,但必须按父序列的顺序(例如ABCBDAB的子序列可为A、B、AB、AAB....),他和字串的区别是,字串子集必须是连续的
最大公共子序列是多个序列的公共子序列最大长度(例如:ABCBDAB和BDCABA的最大公共子序列大小为4,BCBA、BDAB、BCAB都是最大公共子序列)
最长公共子序列的长度为c[i,j],递归式如下:
序列1:0ABCBDAB
序列2:0BDCABA
下图为递归子问题的各个最长公共子序列的长度
我白话的讲解一下这个怎么求
例如第四行,第七列的2是怎么求出的
他对应的行是D,列是D,他们是相等的,他的值就等于他的左上角(第3行,第6列)的值加一,即1+1=2
如果不相等就判断他的上面的值和左边的值的大小,取最大的那个
例如第7行,第6列的3是怎么求出的
他对应的行是B,列是A,他们是不相等的,上面的值为3,左边的值为2,3>2,所以取3
| 0 | A | B | C | B | D | A | B | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| B | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
| D | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 |
| C | 0 | 0 | 1 | 2 | 2 | 2 | 2 | 2 |
| A | 0 | 1 | 1 | 2 | 2 | 2 | 3 | 3 |
| B | 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 |
| A | 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 |
他的时间复杂度为O(n*m)
#include#include #include int **c; //二维数组指针,存放递归求出的各最大公共子序列个数 int Get_Max_Num_Sequence(char a[], char b[], int i, int j){ if (c[j][i] != 0) //表中有数据,直接查表,减少重复操作 { return c[j][i]; } if(i == 0 || j == 0){ c[j][i] = 0; }else if (a[i] == b[j]) { c[j][i] = Get_Max_Num_Sequence(a, b, i-1, j-1) + 1; } else{ int g = Get_Max_Num_Sequence(a, b, i-1, j); int h = Get_Max_Num_Sequence(a, b, i, j-1); if(g > h){ c[j][i] = g; }else{ c[j][i] = h; } } return c[j][i]; } int Max_Num_Sequence(char a[], char b[]){ //动态分配二数组空间 c = (int **)calloc(strlen(b), sizeof(int *)); for (int i = 0; i < strlen(b); i++) { c[i] = (int *)calloc(strlen(a), sizeof(int)); } return Get_Max_Num_Sequence(a, b, strlen(a)-1, strlen(b)-1); } void show(char a[], char b[], int i, int j){ if(c[j][i] == 0){ printf("n"); return; } if(a[i] == b[j]){ show(a, b, i-1, j-1); printf("%c", a[i]); }else{ if(c[j][i-1] >= c[j-1][i]){ show(a, b, i-1, j); }else{ show(a, b, i, j-1); } } } int main(void){ char a[] = "0ABCBDAB"; char b[] = "0BDCABA"; printf("最大公共子序列数:%dn", Max_Num_Sequence(a, b)); for (int j = 0; j < strlen(b); j++) { for (int i = 0; i < strlen(a); i++) { printf("%d ", c[j][i]); } printf("n"); } printf("其中一条子序列为:"); show(a, b, strlen(a)-1, strlen(b)-1); return 0; }
结果:



