算法分析与设计(二)

本文深入解析动态规划在编辑距离计算和邮差问题中的应用,详细阐述递推公式和算法设计,探讨子问题划分与最短路径求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划

  • 编辑距离(Levenshtein距离)

比较两个字符串时,若字符串xxx长度为m,字符串yyy长度为n。
假设这两个字符串之间的编辑距离为E(m,n)E(m,n)E(m,n)
要通过动态规划的方式解决它,那就需要将这样一个问题划分为子问题E(i,j)E(i,j)E(i,j),子问题表示串xxx中前iii个字符与串yyy中前jjj个字符之间的编辑距离。
当计算子串的编辑距离时,子串的最右边一列对齐时有以下三种情形:

 _x[i]x[i]y[j]_y[j]\ \_ \qquad \qquad x[i] \qquad \qquad x[i] \\ y[j] \qquad \qquad \_ \qquad \qquad y[j] _x[i]x[i]y[j]_y[j]

根据以上的对齐方式,可以得到E(i,j)E(i,j)E(i,j)的递推公式:

E(i,j)=min{1+E(i−1,j), 1+E(i,j−1), diff(i,j)+E(i−1,j−1)};If x[i]==y[i] then diff(i,j)=0, otherwise diff(i,j)=1;E(0,j)=j; E(i,0)=iE(i,j) = min\{ 1+E(i-1,j), \ 1+E(i,j-1), \ diff(i,j)+E(i-1,j-1) \} ; \\ If \ x[i]==y[i] \ then \ diff(i,j)=0,\ otherwise \ diff(i,j)=1; \\ E(0,j)=j; \ E(i,0)=iE(i,j)=min{1+E(i1,j), 1+E(i,j1), diff(i,j)+E(i1,j1)};If x[i]==y[i] then diff(i,j)=0, otherwise diff(i,j)=1;E(0,j)=j; E(i,0)=i

根据以上递推公式,便能计算并填写下列表格,最终的E(m,n)E(m,n)E(m,n)即为最小编辑距离

E(i,j)E(i,j)E(i,j)x[1]x[2]x[i]x[m]
012im
y[1]1
y[2]2
y[j]j
y[n]n

计算编辑距离的时间复杂度为
O(m⋅n)O(m \cdot n)O(mn)

计算出编辑距离后,要想求出字符串的编辑位置,则可以从E(m,n)E(m,n)E(m,n)开始与左边、上边或左上角移动一格的区域中找出最小的一个编辑距离即Edmin=min{E(m−1,n), E(m,n−1), E(m−1,n−1)}Ed_{min}=min\{ E(m-1,n), \ E(m,n-1), \ E(m-1,n-1) \}Edmin=min{E(m1,n), E(m,n1), E(m1,n1)},将其与E(m,n)E(m,n)E(m,n)比较,若两者相等则说明x[m]x[m]x[m]y[n]y[n]y[n]是对齐且相等的;否则认为这一位置是编辑点。同时继续以EdminEd_{min}Edmin对应的位置开始继续以上的步骤。
?
如下图说示,为两字符串的编辑位置。

在这里插入图片描述

  • 邮差问题

给定一个加权完全图G=(V,E)G=(V,E)G=(V,E),每条边都有对应一个权值。试寻找一个简单的环路(不闭合),这个环路经过每个顶点恰好一次,并且总权值最小。
如下所示的图,图中有n=5n=5n=5个顶点,假设起点是A点,则从起点开始逐一访问其余顶点形成的所有可能路径是其余4个点的排列P(n−1n−1)P(^{n-1}_{n-1})P(n1n1),使用动态规划的话,能

在这里插入图片描述

动态规划的解法思路是:
对于一个子集S⊆{1,2,...,n}S\subseteq \{ 1,2,...,n\}S{1,2,...,n}1∈S,j∈S.1 \in S , j \in S.1S,jS.
C(S,j)C(S, j)C(S,j)表示从起点111开始经过了集合SSS中所有顶点一次且终止于jjj的路径的最短长度。将C(S,j)C(S, j)C(S,j)表示为更小的子问题:
C(S,j)=minC(S−{j},i)+dijC({1},1)=0C(S, j) = min C(S- \{ j \}, i) + d_{ij} \\ C(\{ 1\} ,1)=0C(S,j)=minC(S{j},i)+dijC({1},1)=0

有了以上的递推公式,便能进行相应的动态规划算法设计了,先从大小为2的集合S(∣S∣=2,且起点1∈S)S (|S|=2, 且起点1 \in S)S(S=2,1S)开始,赋值C(S,1)=∞C(S, 1) = \inftyC(S,1)=,找出SSS中的元素j(j≠1,j非起点)j(j \neq1,j非起点)j(j̸=1j),对C(S,j)C(S,j)C(S,j)执行上述递推公式。之后逐渐扩大集合S的大小直至nnn,并重复上述步骤。

伪代码:
C({1},1)=0C(\{ 1\} ,1)=0C({1},1)=0
for h=2 to n do
for all subsets S⊆{1,2,...,n}S \subseteq \{1,2,...,n \}S{1,2,...,n} of size h and containing 1 do
   C(S,1)=∞C(S,1) = \inftyC(S,1)=
   for all j∈S,j≠1j \in S, j \neq 1jS,j̸=1 do
    C(S,j)=minC(S−{j},i)+dijC(S, j) = min C(S- \{ j \}, i) + d_{ij}C(S,j)=minC(S{j},i)+dij
return minjC({1,2,...,n},j)+dj1min_j C( \{ 1,2,...,n \}, j) +d_{j1}minjC({1,2,...,n},j)+dj1

这种算法思路清晰,但是在实现算法的时候,需要设计合适ADT来表示图及顶点集合,我尝试过编写代码,但限于没有较好的ADT实现思路,我便放弃了 ?。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值