leetcode 72. Edit Distance

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.

You have the following 3 operations permitted on a word:

  1. Insert a character
  2. Delete a character
  3. Replace a character

Example 1:

Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation: 
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')

Example 2:

Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation: 
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')

 

以下五月份写的思路不正确,下面十月份写的解析是正确的。

这题看了网上的很多资料,发现很多解释了该怎么做,但为什么这么做对,基本上没解释。状态转移方程是不复杂的,难的是状态转移方程为什么这么构造。结合知乎上网友的回答https://www.zhihu.com/question/23139644 谈谈自己的理解。

假设A字符串匹配B字符串,首先有几条性质:

1.A中插入的某个字符为了对应B中的某个字符,此后A和B中此字符都不会再改变了。

2.A中变换的某个字符为了对应B中的某个字符,此后A和B中此字符都不会再改变了。

3.A中的操作可以交换次序。

4.A中的插入等效于B中的删除。

5.A最小编辑距离到B,等效于B最小编辑距离到A

所以当A来匹配B可以分为这么几种情况:

1. A中的最后一个字符i删除,此时基于以上性质3可看做A中前面i-1个字符最小编辑距离到B,然后在删除A最后一个字符,此时状态转移方程最小编辑距离为dp[i][j]=dp[i-1][j]+1。

2.A中的最后一个字符i对应B中的最后一个字符j(不等就替换,相等就不变),此时基于以上性质2,3可知A中前面i-1个字符最小编辑距离到B中前j-1个字符,再处理最后一个字符,此时状态转移方程最小编辑距离为dp[i][j]=dp[i-1][j]+1,dp[i-1][j-1]+(word1.charAt(i-1)==word2.charAt(j-1)?0:1)

3.A中的最后一个字符i对应B中的其他字符,此时基于以上性质1,2,3可知,此时的编辑距离大于:A中前面i-1个字符最小编辑距离到B中前k-1(k≠j)个字符,再加上在A后面插入j-(k-1)个与B中对应相同的字符。基于性质4,5,等价于B中前面k-1个字符最小编辑距离到A中前i-1个字符,再加上在B中删除最后j-(k-1)个字符。再根据性质3,这些情况的最小编辑距离都大于等于  B中前面j-1个字符最小编辑距离到A中前i个字符,再删除B中最后一个字符j时的总编辑距离。此时状态转移方程最小编辑距离dp[i][j]=dp[i][j-1]+1。

上面3可以简化理解当A对应B中的其他字符k,根据上面性质,等价于B中K后面的字符要全部删除,其蕴含于删除B中最后一个元素的情况。

另外所有情况都蕴含在上面3中情况中。

此题还需要再思考的更透彻。

 

另一种理解根据上面的性质4,A和B最后一个字符只会出现3种情况,删除A最后一个字符,删除B最后一个字符,A和B都不删。

public int minDistance(String word1, String word2) {
        int[][] dp=new int[word1.length()+1][word2.length()+1];//d[i][j]表示第i和j个字符匹配
        for(int i=1;i<word1.length()+1;i++){
            dp[i][0]=i;
        }
        for(int i=1;i<word2.length()+1;i++){
            dp[0][i]=i;
        }
        for(int i=1;i<word1.length()+1;i++){
           for(int j=1;j<word2.length()+1;j++){
                dp[i][j]=Math.min(dp[i][j-1]+1,Math.min(dp[i-1][j]+1,dp[i-1][j-1]+(word1.charAt(i-1)==word2.charAt(j-1)?0:1)));
           } 
        }
        return dp[dp.length-1][dp[0].length-1];
    }

===============================2018.10.13=========================================================

上面理解的不透彻,正确理解如下:

#         dp[i][j]表示第i和j个字符匹配,dp[0][0]表示空字符,因为空字符也作为一种情况用于递推
#         找一个完备事件组,事件组为子问题,
#         在这之前要明确编辑距离的性质,word1每个字符可看做与word2中某个字符对应,不对应即删除,剩下的字符最小编辑               距离到另一个字符
#         word1插入字符对应可看做word2中对应字符的删除
#         事件组:word1的最后一个字符是否对应word2,
#         情况1:不对应,删除;情况2:对应word2最后一个,情况3对应word2其他字符
#         情况3较为特殊,必定要在word1之后插入字符,否则就不对应,就等效在word2中删除对应字符,这种情况下word2的最             后一个字符必定删除 
#         递推式:dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+word1[i]==word2[j]?0:1),

class Solution:
        dp=[[0 for j in range(len(word2)+1)] for i in range(len(word1)+1)]
        dp[0][0]= 0
        for i in range(1,len(word1)+1):
            dp[i][0]=i
        for j in range(1,len(word2)+1):
            dp[0][j]=j
        for i in range(1,len(word1)+1):
            for j in range(1,len(word2)+1):
                dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+ (0 if word1[i-1]==word2[j-1] else 1))
        return dp[len(dp)-1][len(dp[0])-1]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值