看完算法导论关于这部分内容之后的总结:
关于最长公共子序列问题:
给定两个子序列 X=<X1, X2, X3 , .... , Xm > ; Y=<Y1, Y2, Y3 ,..., Yn>,求X和Y长度最长的公共子序列。
解决方法:
首先先要了解LCS的最优子结构,令X=<X1, X2, X3 , .... , Xm > ; Y=<Y1, Y2, Y3 ,..., Yn>为两个子序列,Z = <Z1,Z2,... ,Zk>为X和Y的任意LCS。
1、如果 Xm = Yn , 则 Zk = Xm = Yn 且 Zk-1 是 Xm-1 和 Yn-1 的一个LCS;
2、如果 Xm ≠ Yn , 则 Zk ≠ Xm ,意味着 Z 是Xm-1和Y 的一个LCS;
3、如果 Xm ≠ Yn , 则 Zk ≠ Yn ,意味着 Z 是X和Yn-1 的一个LCS;
求解最长公共子序列主要用到以下公式
伪代码分析
LCS_LENGTH(X,Y)
1、 m = X.length
2、 n = Y.length
3、 for i = 1 to m
4、 c[i,0] = 0 //c[][]计算表项
5、 for j =0 to m
6、 c[0,j] = 0
7、 for i = 1 to m
8、 for j = 1 to n
9、 if Xi == Yj //先比较Xi 和 Yj 是否相等
10、 c[i,j] = c[i-1][j-1] + 1 //相等的话就将c[i,j]的值加上其上一个对角线元素的值
11、 b[i,j] = "↖" //并将当前单元格设置成"↖"
12、 elseif c[i-1][j] ≥ c[i][j-1] //Xi 和 Yj 不相等,则比较当前单元格上方和左方单元格的值
13、 c[i,j] = c[i-1][j] //如果上方单元格的值大于等于其左方单元格的值,则当前单元格设置成"↑"
14、 b[i][j] = "↑"
15、 else
16、 c[i][j] = c[i][j-1]
17、 b[i][j] = "←" //否则设置成"←"
18、return c and b
根据以上伪代码构造出的表
执行4,5行后得到下面这个表:
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ||||||
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
然后以行为主序开始扫描:
我们可以先找出 Xi == Yj 的单元格,标记它的值和箭头方向 。
当i = 1时,扫描第一行中为(A,A)的单元格,标记为↖,并执行c[i][j] = c[i-1][j-1] + 1;
其它的单元格按照12-17行的代码进行标记,如(X1,Y1) = (A,B),两者不相同,所以比较(X1,Y1)上方和左方的单元格的值。哪个的值大,箭头就指向哪个单元格,并将c[i][j]的值设置为c[i-1,j],c[i,j-1]中具有较大值的单元格的值。
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
。。。。
最后得到以下表格:
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ↖1 | ←1 | ←1 | ↑1 | ↖2 | ←2 |
3 | C | 0 | ↑1 | ↑1 | ↖2 | ←2 | ↑2 | ↑2 |
4 | B | 0 | ↖1 | ↑1 | ↑2 | ↑2 | ↖3 | ←3 |
5 | D | 0 | ↑1 | ↖2 | ↑2 | ↑2 | ↑3 | ↑3 |
6 | A | 0 | ↑1 | ↑2 | ↑2 | ↖3 | ↑3 | ↖4 |
7 | B | 0 | ↖1 | ↑2 | ↑2 | ↑3 | ↖4 |
↑
得到上面的表格之后,执行以下函数得到LCS
PRINT-LCS(b, X, X.length, Y.length)
1、if X.length==0 || Y.length == 0
2、 return;
3、if b[i,j] == "↖"
4、 PRINT-LCS(b, X, X.length-1, Y.length-1)
5、 print Xi
6、elseif b[i,j] == "↑"
7、 PRINT-LCS(b, X, X.length-1, Y.length)
8、else
9、 PRINT-LCS(b, X, X.length, Y.length-1)
j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
i | Yj | B | D | C | A | B | A | |
0 | Xi | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | A | 0 | ↑0 | ↑0 | ↑0 | ↖1 | ←1 | ↖1 |
2 | B | 0 | ||||||
3 | C | 0 | ||||||
4 | B | 0 | ||||||
5 | D | 0 | ||||||
6 | A | 0 | ||||||
7 | B | 0 |