第十五章 动态规划

定义

  • 类似分治法的一种编程方法

最长公共子序列问题(LCS)

1.问题描述:

  • 给出两个序列:X[1…m], Y[1…n],找出一个最长的公共子列;需要注意的是,最长的公共子列往往不唯一。

2. 具体举例:

  • X=ABCBDAB,Y=BDCABA
    LCS为最长公共子列有三个:BDAB, BCBA及BCAB
    注:以下将最长公共子序列简称为LCS

3. 求解

  • 暴力法:考虑最坏情况下的时间复杂度。

    1.先寻找X中的所有子序列,共有 2 m 2^m 2m种可能,因此时间复杂度为 O ( 2 m ) O(2^m) O(2m)

    2.检查得到的子序列是否为Y的子序列,最多需与Y序列比较n个元素,因此时间复杂度为 O ( n ) O(n) O(n)

    因此总时间复杂度为 O ( n ⋅ 2 m ) O(n·2^m) O(n2m)非常慢!(原话是:slow

4. 如何用更快的方法?

  • 考虑如下简化问题:
    a. 如何计算LCS的长度?
    b. 将上述拓展求解

5. 引入以下定义:

∣ S ∣ : 为 序 列 S 的 长 度 ; \left|S\right|:为序列S的长度; S:S c [ i , j ] = ∣ L C S ( X [ 1 … i ] , Y [ 1 … j ] ) ∣ c\left[i, j\right] = \left|LCS\left(X\left[1\dots i\right], Y\left[1\dots j \right]\right)\right| c[i,j]=LCS(X[1i],Y[1j])

  • 个人理解: c [ i , j ] c\left[i, j\right] c[i,j]表示 X [ 1 … i ] , Y [ 1 … j ] X\left[1\dots i\right], Y\left[1\dots j \right] X[1i],Y[1j]这两个序列的最长公共子序列的长度;因此 X , Y X,Y X,Y的最长公共子序列长度为 c [ m , n ] c\left[m, n\right] c[m,n]

6. 如何计算 c [ i , j ] c\left[i, j\right] c[i,j]

  • 可按以下公式: c [ i , j ] = { c [ i − 1 , j − 1 ] + 1 X [ i ] = Y [ j ] m a x { c [ i − 1 , j ] , c [ i , j − 1 ] } o t h e r c\left[i, j\right] = \begin {cases} c\left[i-1, j-1\right]+1 & X\left[i\right]=Y\left[j\right] \\ max\lbrace c\left[i-1, j\right], c\left[i, j-1\right] \rbrace& other \end{cases} c[i,j]={c[i1,j1]+1max{c[i1,j],c[i,j1]}X[i]=Y[j]other

  • 证明:先考虑 X [ i ] = Y [ i ] X\left[i\right]=Y\left[i\right] X[i]=Y[i]的情况,引入
    Z [ 1 , … , k ] = L C S ( X [ i ] , Y [ j ] ) Z\left[1,\dots ,k\right]=LCS\left( X\left[i\right],Y\left[j\right] \right) Z[1,,k]=LCS(X[i],Y[j])由定义可得以下结论
    c [ i , j ] = k c\left[i,j\right]=k c[i,j]=k Z [ k ] = X [ i ] = ( Y [ j ] ) Z\left[k\right]=X\left[i\right]=(Y\left[j\right]) Z[k]=X[i]=(Y[j])
    个人理解:引入的 Z Z Z是表示具体的最长公共子序列,通过其下标可以引用到具体的字符

    ∵ X [ i ] = Y [ j ] \because X\left[i\right]=Y\left[j\right] X[i]=Y[j]

    ∴ 在 原 序 列 上 加 上 X [ i ] o r Y [ j ] 可 以 让 公 共 子 序 列 更 长 \therefore在原序列上加上X\left[i\right]orY\left[j\right]可以让公共子序列更长 X[i]orY[j]

    ∴ Z [ 1 , … , k − 1 ] 是 X [ 1 , … i − 1 ] 及 Y [ 1 , … , j − 1 ] 的 最 长 公 共 子 序 列 \therefore Z\left[1,\dots ,k-1\right]是X\left[1,\dots i-1\right]及Y\left[1,\dots ,j-1\right]的最长公共子序列 Z[1,,k1]X[1,i1]Y[1,,j1]

    假设存在更长的公共子序列 W W W,则 ∣ W ∣ > k − 1 \left|W\right|\gt k-1 W>k1,将 W ∣ ∣ Z [ k ] ( 将 两 个 字 符 合 并 ) W||Z[k](将两个字符合并) WZ[k](),则 W ∣ ∣ Z [ k ] W||Z[k] WZ[k]是公共子序列,且长度 > k ( ∵ ∣ W ∣ > k − 1 ) \gt k(\because |W|>k-1) >k(W>k1),与之前的 Z Z Z的定义矛盾。
    ∴ c [ i − 1 , j − 1 ] = k − 1 \therefore c\left[i-1,j-1\right]=k-1 c[i1,j1]=k1
    ∴ c [ i , j ] = c [ i − 1 , j − 1 ] + 1 \therefore c\left[i,j\right]=c\left[i-1,j-1\right]+1 c[i,j]=c[i1,j1]+1

    对于另一种情况可通过相同方式证明,动态规划问题可以分解为子问题的最优,这体现了动态规划的一个特征,Optimal Substructure(最优子结构)

7.动态规划的特征

  • Optimal Substructure(最优子结构):最优解的问题包含了子问题的最优解。
  • Overlapping Subproblems(重叠子问题): 递归问题的解在子问题中重复多次。

8.递归算法的伪代码

```
LCS(x, y, i, j)
	if x[i]==y[i]
		then c[i, j]=LCS
		else c[i, j]=max{LCS(x, y, i-1, j), LCS(x, y, i, j-1)}
	return c[i, j]
```
  • 举例:
    m = 7 , n = 6 m=7, n=6 m=7,n=6,每次考虑最差的情况,即 X [ i ] 与 Y [ j ] 不 相 等 X\left[i\right]与Y\left[j\right]不相等 X[i]Y[j],则得到以下递归树:

递归树

  1. 此递归树的高度: H e i g h t = m + n Height=m+n Height=m+n,因此求解整个递归树的时间复杂度为 O ( 2 m + n ) O(2^{m+n}) O(2m+n),直接求解会非常缓慢。
  2. 观察递归树结构,发现其中有许多分支重复,如下图框内部分,这为快速求解提供了思路,同时这也是动态规划问题的另一个特征,Overlapping Subproblems(重叠子问题)。因此实际只包含了 m × n m\times n m×n个不重复的子问题。
    重复项

9.记账法(Memoization)

  • 引入了记账方法计算每个单元的代价,伪代码如下:
LCS(x,y,i,j)
if c[i,j]=nil then #仅加入了这一行逻辑判断,其余与递归法相同。
	if x[i]==y[j] 
	then c[i,j]=c[i-1,j-1]+1
	else c[i,j]=max{LCS(x, y, i-1, j), LCS(x, y, i, j-1)}

10.自上向下填表(真·动态规划)

  • 利用自上向下填表法进行求解:

初始化为如下表:

ABCBDAB
0000000
B0
D0
C0
A0
B0
A0

根据下式自上向下进行填表:
c [ i , j ] = { c [ i − 1 , j − 1 ] + 1 X [ i ] = Y [ j ] m a x { c [ i − 1 , j ] , c [ i , j − 1 ] } o t h e r c\left[i, j\right] = \begin {cases} c\left[i-1, j-1\right]+1 & X\left[i\right]=Y\left[j\right] \\ max\lbrace c\left[i-1, j\right], c\left[i, j-1\right] \rbrace& other \end{cases} c[i,j]={c[i1,j1]+1max{c[i1,j],c[i,j1]}X[i]=Y[j]other

ABCBDAB
0000000
B00111111
D00111222
C00122222
A01122233
B01223334
A01223344
  • 分析
    1.如何重构最长子序列:回溯法
    2.空间复杂度:最小实际上可以达到 m i n { m , n } min\lbrace m,n\rbrace min{m,n}(每次计算只需要三个值的信息,与前两行无关)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值