leetcode 72.Edit Distance

来源:互联网 发布:录音配乐软件 编辑:程序博客网 时间:2024/06/11 14:48

编辑距离,dp


题意:

给你两个字符串s1和s2,和三种操作:

1.插入一个字符

2.删除一个字符

3.替换一个字符

问至少要多少次操作才能从s1变换到s2.


思路:

编辑距离,很有用的一个概念.模糊匹配等地方都会出现.

方法是dp,和求最大公共子序列十分像,但是我一直不会.

dp[i][j]表示s1长度为i的前缀和s2长度为j的前缀的编辑距离.

初始化是dp[i][0]=i,dp[0][j]=j

递推公式是dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+(s1[i-1]!=s2[j-1]))

答案是dp[s1.len][s2.len]


递推公式中的三项分别对应删除,插入,替换(或无需替换).

时间复杂度显然是O(n2),空间复杂度也是O(n2),但可以用滚动数组优化到O(n).


证明:

由于我不会,所以证明了一下正确性.

先有四个比较显然的结论:

(1)操作之间的顺序颠倒不影响答案

(2)如果s1和s2有相同的前缀或后缀,那么删掉它们不影响答案

(3)s1的每个字符最多只被操作一次(替换或删除)

(4)如果s1的最后一个字符没被删除,但操作后不是s2的最后一个字符,那么s2的最后一个字符肯定是插入的.


现在枚举最优变换下,s1的最后一个字符要作什么操作.

1.删除

以s1="be",s2="db"为例子,最佳路径可以是"be"->"dbe"->"db".

我们把这个操作放在一开始进行,那么dp["be"]["db"]=dp["b"]["db"]+1(删除)

2.替换

(1)这个字符替换后是s2的最后一个字符

以s1="be",s2="sbd"为例子,最佳路径可以是"be"->"sbe"->"sbd".

我们把这个操作放在一开始进行,那么dp["be"]["sbd"]=dp["b"]["sb"]+1(替换)

(2)这个字符替换后不是s2的最后一个字符

以s1="be",s2="bfd"为例子,最佳路径可以是"be"->"bf"->"bfd".

由于被替换后不是s2的最后一个字符,那么它在s2的最后一个字符肯定是插入的.

我们把插入操作放在一开始进行,此时有dp["be"]["bfd"]=dp["be"]["bf"]+1(插入)

3.没操作

(1)这个字符是s2的最后一个字符

以s1="be",s2="dke"为例子,最佳路径可以是"be"->"dbe"->"dke".

'e'同时是s1和s2的后缀,此时有dp["be"]["dke"]=dp["b"]["dk"](无需替换)

(2)这个字符不是s2的最后一个字符

以s1="be",s2="bad"为例子,最佳路径可以是"be"->"ba"->"bad".

由于'e'是s1的最后一个字符,但在s2并不是最后一个,那么s2的最后一个字符肯定是插入的.

我们把插入操作放在一开始进行,此时有dp["be"]["bad"]=dp["be"]["ba"]+1(插入)


总结:

dp,dp[i][j]表示s1长度为i的前缀和s2长度为j的前缀的编辑距离.


0 0
原创粉丝点击