这其实是一道经典的题目——Edit distance
很自然地我们会想到,变换两个字符串所需的操作次数与这两个字符串的匹配程度有关。
举个栗子 SNOWY & SUNNY
以下是几种可能的情况
S – N O W Y
S U N N – Y
操作数:3– S N O W – Y
S U N – – N Y
操作数:5“–”意味着一次插入或删除操作。
当它们匹配程度最高时,便会有最小的操作数产生,如果你枚举的话,可以发现,第一种修改情况的操作数是最少的,没有比这更少的操作数:插入
U
,将
总而言之,两个字符串之间有很多种匹配方案,如果暴力搜索无疑是低效的。
在这里,我们引入一个全新的思考问题的视角:
我们把输入的两个字符串
想象一下,假设我们已经获得
x[1⋅⋅⋅i−1]和y[1⋅⋅⋅j−1]
、
x[1⋅⋅⋅i]和y[1⋅⋅⋅j−1]
、
x[1⋅⋅⋅i−1]和y[1⋅⋅⋅j]
匹配时的最小操作数,分别记为
dp(i−1,j−1)、dp(i,j−1)、dp(i−1,j)
,
此时当我们要匹配
x[1⋅⋅⋅i]和y[1⋅⋅⋅j]
时,我们会面临如下3种选择:
1.删除 x[i]
x[i]
−2.插入
y[j] −
y[j] 3. x[i]→y[j]
x[i]
y[j]
以下重点!
以第一种情况为例:删除
x[i]
,操作数为
1
,那么此时
题目要求最少的操作数,那么我们最好的方案便是在每一步时都求得最少的操作数,按以上思路继续,便可获得整体最小的操作数。(由于以上式子 i,j 为 1...m,1...n 中任意一个数,故以上思路存在普遍性)
即
其中,当 x[i]!=y[i] 时, diff(i,j)=1 ,表示需要一次修改操作;当 x[i]==y[i] 时, diff(i,j)=0 ,表示此时不需要修改操作
如此,我们刚好可以用一个二维数组 dp[i][j] 表示 dp(i,j) ,让 i,j 分别从小到大循环,来处理 x[i] 和 y[i] 的情形。最后 dp[m][n] 即为所求的最小值。
伪代码可以这么写
for i=0,1,2,...,m:
dp[i][0]=i
for j=0,1,2,...,n:
dp[0][j]=j
for i=1,2,...,m:
for j=1,2,...,n:
dp(i,j)=min{dp(i−1,j)+1,dp(i,j−1)+1,dp(i−1,j−1)+diff(i,j)}
其实这种方法叫做动态规划 Dynamic programming,dp是它的缩写,同学们可以自己去了解一下这种思想方法。