问题分析
给定两个序列X={x1,x2,…,xm} 和 Y={y1,y2,…,yn},找出X和Y的一个最长的公共子序列。
这里的讲解是参照趣学算法一书,此书的地址在Dijkstra的文章末。
分析最优解的结构特征
假设已经知道 Zk={z1,z2,…,zk} 是X={x1,x2,…,xm} 和 Y={y1,y2,…,yn的最长公共子序列。那么可以分3中情况讨论。
Xm=Yn=Zk 那么Zk-1={z1,z2,…,zk-1}是 Xm-1 和 Yn-1的最长公共子序列
Xm!=Yn Xm!=Zk 我们可以 把Xm去掉,那么Zk是Xm-1和Yn的最长公共子序列
Yn!=Xm Yn!=Zk 同上理,Xm和Yn-1
建立最优值的递归式
- Xm=Yn=Zk: 那么c[i][j]=c[i-1][j-1]+
- Xm != Yn: 那么 c[i][j]=max{c[i][j-1],c[i-1][j]}
所以递归式为:
底向上计算最优值,并记录最优值和最优策略
构造最优解
上面的求解过程只是得到了最长公共子序列的长度,并不知道最长公共子序列是什么。
这里比较重要,我就直接贴图了,这样看清楚点。
算法设计
(1)确定合适的数据结构
采用二维数组c[][]来记录最长公共子序列的长度,二维数组b[][]来记录最长公共子序列的长度来源
(2)初始化
输入两个字符串s1,s2,初始化c[][]第一行第一列为0
(3)循环阶段
(4)构造最优解
完美图解
伪代码详解
(1)最长公共子序列求解函数
首先计算两个字符串长度,然后从i=1开始,s1[0]与s2中的每一个字符比较
void LCSL(){
for(int i=1;i<=len1;i++){
//控制s1序列
for(int j=1;j<=len2;j++){
//控制s2序列
if(s1[i-1]==s2[j-