Unit2_2:动态规划DP

2023-11-09 12:30
文章标签 动态 规划 dp unit2

本文主要是介绍Unit2_2:动态规划DP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、最长公共子序列
    • 分析
    • 填表
    • 伪代码
    • 过程
    • 时间复杂度
  • 二、最长公共子串问题
    • 分析
    • 过程
    • 时间复杂度
  • 最小编辑距离
    • 背景
    • 分析
    • 状态转移方程
    • 填表
    • 伪代码
    • 案例

一、最长公共子序列

子序列:指从原序列中选取出来的具有相对顺序的一组元素,而这些元素不一定是连续的
在这里插入图片描述
X和Y的最长公共子序列是Z。

分析

在这里插入图片描述
Z k = ( z 1 , . . . , z k ) Z_k=(z_1,...,z_k) Zk=(z1,...,zk) X [ 1.. i ] X[1..i] X[1..i] Y [ 1.. j ] Y[1..j] Y[1..j]的最长公共子序列( L C S LCS LCS),最大值用 d i , j d_{i,j} di,j表示

若 x i = y j ,则 z k = x i = y j ,且 z k − 1 是 X [ 1.. i − 1 ] 和 Y [ 1.. j − 1 ] 的 L C S 。 若x_i = y_j,则z_k = x_i = y_j,且z_{k−1}是X[1..i−1]和Y[1..j−1]的LCS 。 xi=yj,则zk=xi=yj,且zk1X[1..i1]Y[1..j1]LCS

若 x i ≠ y j ,这意味着 L C S 不以 x i 结束,也不以 y j 结束。 那么 Z k 要么是 X [ 1.. i − 1 ] 和 Y [ 1.. ] j ] 的 L C S ,或 X 的 L C S [ 1.. i ] 和 Y [ 1.. j − 1 ] 。 我们继续使用两种情况下更大的 L C S 计数。 若xi \neq yj,这意味着LCS不以xi结束,也不以yj结束。\\ 那么Z_k要么是X [1..i−1]和Y[1..]j]的LCS,或X的LCS [1..i]和Y [1..j−1]。\\我们继续使用两种情况下更大的LCS计数。 xi=yj,这意味着LCS不以xi结束,也不以yj结束。那么Zk要么是X[1..i1]Y[1..]j]LCS,或XLCS[1..i]Y[1..j1]我们继续使用两种情况下更大的LCS计数。

因此可得:

d i , j = { d i − 1 , j − 1 + 1 i f x i = y i m a x ( d i − 1 , j , d i , j − 1 ) i f x i ≠ y i d_{i,j}=\left\{ \begin{array}{ll} d_{i-1,j-1} +1& if \space x_i=y_i \\ max ( d_{i-1,j} , d_{i,j-1} )& if \space x_i \neq y_i \nonumber \end{array} \right. di,j={di1,j1+1max(di1,j,di,j1)if xi=yiif xi=yi

填表

在这里插入图片描述
同样,我们创建另一个 m × n m×n m×n矩阵 p [ i , j ] p[i, j] p[i,j],对于 1 ≤ i ≤ m ,且 1 ≤ j ≤ n 1≤i≤m,且1≤j≤n 1im,且1jn,来存储指向计算中使用的元素的箭头。因此,我们可以稍后重建 L C S LCS LCS的元素

伪代码

Longest-Common-Subsequence(X,Y)
//Initialization
for i ← 0 to m dod[i,0] ← 0
end
for j ← 0 to m dod[0,j] ← 0
end//Dynamic Programming
for i ← 0 to m dofor j ← 0 to m doif xi = yi thend[i,j] ← d[i-1,j-1]+1p[i,j]="LU"    //"LU" indicates left up arrowendendelse if d[i-1,j] >= d[i,j-1] thend[i,j] ← d[i-1,j]p[i,j]="U"    //"U" indicates up arrowendelsed[i,j] ← d[i,j-1]p[i,j]="L"    //"L" indicates left arrowend
end
return d,p
Print-LCS(p,X,i,j)
if i is equal to 0 or j is equal to 0 thenreturn NULL;
end
if p[i,j] is equal to "LU” thenPrint-LCS(p,X,i-1,j-1);print xi;
end
else if p[i,j] is equal to "U”  thenPrint-LCS(p,X,i-1,i);
end
elsePrint-LCS(p,X,i,j-1);
end

过程

在这里插入图片描述
然后根据p的指示找出最长公共子序列即可

时间复杂度

两层循环,时间复杂度 T ( n ) = O ( n m ) T(n)=O(nm) T(n)=O(nm)

二、最长公共子串问题

子串:指从原序列中选取出来的具有相对顺序的一组元素,而且这些元素一定是连续的
在这里插入图片描述

分析

此题和上一个 L C S LCS LCS不同,不能设 Z k = ( z 1 , . . . , z k ) Z_k=(z_1,...,z_k) Zk=(z1,...,zk) X [ 1.. i ] X[1..i] X[1..i] Y [ 1.. j ] Y[1..j] Y[1..j]的最长公共子串( L C S LCS LCS),最大值用 d i , j d_{i,j} di,j表示。因为以此结尾的 x i 和 y j x_i和y_j xiyj若相同, d i , j d_{i,j} di,j也不一定等于 d i − 1 , j − 1 + 1 d_{i-1,j-1}+1 di1,j1+1,可能字串在中间,无法递归。

DP无法进行下去时可以加以限制,我们只需要定义 Z k = ( z 1 , . . . , z k ) Z_k=(z_1,...,z_k) Zk=(z1,...,zk) X [ 1.. i ] X[1..i] X[1..i] Y [ 1.. j ] Y[1..j] Y[1..j] x i x_i xi或和 y j y_j yj结尾的最长公共子串( L C S LCS LCS),最大值用 d i , j d_{i,j} di,j表示,此时就能递归进行下去了。

若 x i = y j ,则 z k = x i = y j ,且 z k − 1 是 X [ 1.. i − 1 ] 和 Y [ 1.. j − 1 ] 的 L C S 。 若x_i = y_j,则z_k = x_i = y_j,且z_{k−1}是X[1..i−1]和Y[1..j−1]的LCS 。 xi=yj,则zk=xi=yj,且zk1X[1..i1]Y[1..j1]LCS

若 x i ≠ y j ,这意味着 L C S 不以 x i 结束,也不以 y j 结束。 若xi \neq yj,这意味着LCS不以xi结束,也不以yj结束。 xi=yj,这意味着LCS不以xi结束,也不以yj结束。

d i , j = { d i − 1 , j − 1 + 1 i f x i = y i 0 i f x i ≠ y i d_{i,j}=\left\{ \begin{array}{ll} d_{i-1,j-1} +1& if \space x_i=y_i \\ 0& if \space x_i \neq y_i \nonumber \end{array} \right. di,j={di1,j1+10if xi=yiif xi=yi

最后,我们可以通过计算所有可能的结束位置i和j的最大值来得到最长的公共子串。
L C S ( X , Y ) = m a x ( d i , j ) LCS(X,Y)=max(d_{i,j}) LCS(X,Y)=max(di,j)
填表也是一致
在这里插入图片描述
但这里维护位置就很简单了,因为子串是连续的,因此只需要记录末尾位置和最大长度即可:用 l m a x l_{max} lmax p m a x p_{max} pmax分别存储公共子字符串的最大长度及其位置i(或j)。所以,我们可以稍后从X(或Y)重建元素。


Longest-Common-Substring(X,Y)
//Initialization
lmax ← 0
pmax ← 0
for i ← 0 to m dod[i,0] ← 0
end
for j ← 0 to n dod[0,j] ← 0
end//Dynamic Programming
for i ← 1 to m dofor j ← 1 to n doif xi != yi thend[i,j] ← 0endelsed[i,j] ← d[i-1,j-1]if d[i,j]>lmax thenlmax ← d[i,j]pmax ← iendendendend
return lmax,pmax
Print-LCS(X,lmax,pmax)
if lmax is equal to 0 thenreturn NULL;
end
for i ← (pmax-lmax+1) to pmax doprint xi
end

过程

在这里插入图片描述

时间复杂度

两层循环,时间复杂度 T ( n ) = O ( n m ) T(n)=O(nm) T(n)=O(nm)

最小编辑距离

背景

当把“algorithm”误输入为“algorithm”时,系统可能自动帮助搜索最优的调节词矫正。可运用于机器翻译,信息提取和语音识别。

给定两个数组 X = ( x 1 , x 2 , . . . , x m ) , Y = ( y 1 , y 2 , . . . , y n ) 给定两个数组X=(x_1,x_2,...,x_m),Y=(y_1,y_2,...,y_n) 给定两个数组X=(x1,x2,...,xm),Y=(y1,y2,...,yn),编辑距离是将X转换为Y的编辑操作的最小次数

分析

编辑一共有三种操作:
    添加字母
    删除字母
    替换一个字符。
因为实际考虑中每个操作都需要付出相应的代价 c o s t cost cost,为了简化问题,设每个操作 c o s t = 1 cost=1 cost=1

定义 D [ i , j ] 为子字符串 X [ 1.. i ] 和 Y [ 1.. j ] 的最小编辑距离 定义D[i,j]为子字符串X[1..i]和Y [1..j]的最小编辑距离 定义D[i,j]为子字符串X[1..i]Y[1..j]的最小编辑距离

X [ 1.. i ] 变成 Y [ 1.. j ] X[1..i]变成Y [1..j] X[1..i]变成Y[1..j]有三种情况:
   将 X [ 1.. i − 1 ] 变成 Y [ 1.. j ] X[1..i-1]变成Y [1..j] X[1..i1]变成Y[1..j]并删除 X [ i ] X[i] X[i]
       M E D ( c x y − > d a b ) = M E D ( c x − > d a b ) + 1 MED(cxy->dab)=MED(cx->dab)+1 MED(cxy>dab)=MED(cx>dab)+1
   将 X [ 1.. i ] 变成 Y [ 1.. j − 1 ] X[1..i]变成Y [1..j-1] X[1..i]变成Y[1..j1]并插入Y[j]
       M E D ( c x y − > d a b ) = M E D ( c x y − > d a ) + 1 MED(cxy->dab)=MED(cxy->da)+1 MED(cxy>dab)=MED(cxy>da)+1
   如果 X [ i ] ≠ Y [ j ] X[i] \neq Y[j] X[i]=Y[j],将 X [ 1.. i − 1 ] 变成 Y [ 1.. j − 1 ] X[1..i-1]变成Y [1..j-1] X[1..i1]变成Y[1..j1]并将 X [ i ] 替换成 Y [ j ] X[i]替换成Y[j] X[i]替换成Y[j]
       M E D ( c x y − > d a b ) = M E D ( c x − > d a b ) + 1 MED(cxy->dab)=MED(cx->dab)+1 MED(cxy>dab)=MED(cx>dab)+1
       M E D ( c x y − > d a b ) = M E D ( c x − > d a ) + 1 MED(cxy->dab)=MED(cx->da)+1 MED(cxy>dab)=MED(cx>da)+1

状态转移方程

D [ i , j ] = m i n { D [ i − 1 , j ] + 1 D [ i , j − 1 ] + 1 D [ i − 1 , j − 1 ] + { 0 i f X [ i ] = Y [ j ] 1 i f X [ i ] ≠ Y [ j ] D[i,j]=min\left\{ \begin{array}{ll} D[i-1,j] +1\\ D[i,j-1] +1\\ D[i-1,j-1]+\left\{ \begin{array}{ll} 0 & if \space X[i]=Y[j]\\ 1 & if \space X[i] \neq Y[j] \nonumber \end{array} \right.\nonumber \end{array} \right. D[i,j]=min D[i1,j]+1D[i,j1]+1D[i1,j1]+{01if X[i]=Y[j]if X[i]=Y[j]

同时,我们创建另一个矩阵 p [ i , j ] ( 1 ≤ i ≤ m , 1 ≤ j ≤ n ) p[i, j](1≤i≤m, 1≤j≤n) p[i,j](1im,1jn)来存储指向计算中使用的元素的箭头,用于恢复操作的最优序列。

p [ i , j ] = { L e f t i f I n s e r t i o n U p i f D e l e t i o n L e f t U p i f S u b s t i t u t i o n p[i,j]=\left\{ \begin{array}{ll} Left& if \space Insertion\\ Up& if \space Deletion\\ Left Up& if \space Substitution \nonumber \end{array} \right. p[i,j]= LeftUpLeftUpif Insertionif Deletionif Substitution

填表

最初,我们用 j j j填充矩阵 D [ 0 , j ] D[0,j] D[0,j]的第一行,用 i i i填充矩阵 D [ i , 0 ] D[i, 0] D[i,0]的第一列。

空串到一个长为 j j j的串或者长为 i i i的串到空串,最短做法就是一个个删除或者添加。

在这里插入图片描述

伪代码

Minimum-Edit-Distance(X,Y)
//Initialization
for i ← 0 to m dod[i,0] ← ip[i,0]="U'
end
for j ← 0 to m dod[0,j] ← jp[0,j]="L"
end//Dynamic Programming
for i ← 1 to m dofor j ← 1 to n doif xi != yi thenc ← 1endelsec ← 0endif d[i-1][j-1]+c <= d[i-1][j]+1 andd[i-1][j-1]+c <= d[i][j-1]+1 thend[i][j] ←  d[i-1][j-1]+cp[i][j] ←  "LU"endelse if d[i-1][j]+1 <= d[i-1][j-1]+c andd[i-1][j]+1 <= d[i][j-1]+1 thend[i][j] ← d[i-1][j]+1p[i][j] ←  "U"endelsed[i][j] ← d[i][j-1]+1p[i][j] ←  "L"endendreturn d,p
end
Print-MED(p,X,i,j)
if i is equal to 0 or j is equal to 0 thenreturn NULL;
end
if p[i,j] is equal to "LU” thenPrint-MED(p,X,i-1,j-1);if xi = yi thendo nothingendelseprint Substitue xi with yiend
end
else if p[i,j] is equal to "U” thenPrint-MED(p,X,i-1,i);print Delete xi
end
elsePrint-MED(p,X,i,j-1);print Insert xi
end

案例

在这里插入图片描述
根据P找到具体操作路径
在这里插入图片描述

这篇关于Unit2_2:动态规划DP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/376095

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

Java导出Excel动态表头的示例详解

《Java导出Excel动态表头的示例详解》这篇文章主要为大家详细介绍了Java导出Excel动态表头的相关知识,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录前言一、效果展示二、代码实现1.固定头实体类2.动态头实现3.导出动态头前言本文只记录大致思路以及做法,代码不进

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节