当前课程知识点:数据结构(上) > 第一章 绪论(下) > (xc)动态规划 > 01XC-9: LCS:复杂度
这个算法的正确性
是可以得到保证的
准确地讲 是由于它所具有的
某种单调性
这种单调性 可以理解为
在这个算法中 每经过一次递归
无论减而治之 还是分而治之
我们只需要经过一次比对
原问题的规模 总是可以减小
确切地讲
每经过一次比对操作之后
新生成出来的递归实例
所对应的一对序列中
至少有一个的长度
会相对于此前 缩短一个单位
比如说 在最好的情况下
会始终只出现减而治之
而不会出现分而治之的情况
在这种情况下
每一个递归实例
都会缩减为一个
而不是两个递归实例
而且它所对应的
两个序列的长度
都会单调地减少一个单位
所以相应地 这样下去
至多经过这两个序列的
长度总和这么多时间
算法必然就会终止
这个结果非常好
因为这意味着 在这种情况下
我们只需要线性规模的时间
然而 一旦有第二种情况
也就是 分而治之出现
就不那么简单了
因为在这种情况下
原来的那个问题
将会被分解为两个
而不是一个子问题
更糟糕的是呢
这两个子问题的规模之和
居然大致是原来那个问题的两倍
而且在进一步导出的子问题中
也有类似的情况
从而造成总体上 大量的雷同
这种现象 与我们此前所讲的
Fibonacci数的那个递归算法 完全类似
我们可以把刚才那个
表格的局部展开
放大来看一下
为什么会出现这种情况
在这个表格中 任何一个单元
都对应一个递归实例
每一个递归实例
都分别对应于一对序列
每一次 我们都会去比较
它们的末字符
比如说 这里的是LG
这里的是AG 包括这个是LA
如果它们确实是相同的
比如说 这里的情况
刚才我们讲过
它会减而治之地
降解为一个新的问题
这个问题相当于
把原来的这两个序列
相同的末字符都抹掉
我们刚才说 这是好的情况
但是更一般的情况是 不等
比如这里的情况
在这个时候 每一个递归实例
都会转化为两个递归实例
就像我们刚才所说的
这两个递归实例
不仅在数量上增加了
而且总的规模
几乎是原来的两倍
更糟糕的是 它们还会继续地
引发雷同的递归实例
比如 还是这个例子
由这个递归实例会引发
这样两个递归实例
而我们这两个递归实例
都会进而唤醒
这个公共的递归实例
这就是我们所说的雷同
这种重复度是远远超乎
我们的直观想象的
为了就此做一估算
我们不妨从更宏观的角度
来重新审视
刚才我们所制作的这张表格
不妨把其中所有的递归实例
分别按坐标的形式
也就是它们所对应的
那一对序列的长度
表示为n m或者是a b
当然包括最初的0 0
那么我们来问一个问题
为了计算出 最终这个递归实例
也就是n m所对应的解
我们需要唤醒其中
某一个特定的递归实例
也就是a b多少次呢?
其实不难理解
根据这样的行走的方向
我们说最坏的情况下
所唤醒的次数应该等于
介于这两个隔点之间的
所有通路的数目
这样的路径每一条
就对应于a b 被唤醒一次
反之亦然
因此运用一下组合数学
就可以得出
为了计算出最终的这个结果
我们唤醒a b
这个递归实例的次数
应该是等于在它们之间
所有合法通路的总数
也就是n-a 再加上m-b中
去挑选出n-a条
水平路径的总数
这样的方案数
或者等效地
在刚才那么多段路径中
挑选出互补的
m-b条垂直的路径的总数
这个总数是多少呢?
我们不妨取其中的一个特例
也就是0 0来做估算
这个时候a b分别等于0和0
所以这个总数其实也就是总体
这个表格的行和宽的总和
也就是m+n中 去挑选出n
或者等效地挑选出m
如果这个表格是接近
甚至是完全是方形的话
这个总数大致就是2的n次方
没错 我们这里
又再次地碰到了指数
又掉进了指数复杂度的悬坑
下面我们就来看看
如何跳过这个悬坑
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验