LeetCode-Edit Distance 编辑距离与动态规划

作者:disappearedgod
时间:2014-6-18

题目

Edit Distance

  Total Accepted: 9568  Total Submissions: 38449 My Submissions

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character
b) Delete a character
c) Replace a character


解法

借用这道题来讨论一下编辑距离这个话题。

思路

微软实习在2014年春天第一次网上提交代码时候,曾经出过一道跟编辑距离有关的题目。
拿到这道题之前,我们的思路是:
  1. 了解什么是编辑距离
  2. 编辑距离建模
  3. 因为是DP系列题目,所以跳过一些判断直接想能否用DP解
根据这个步骤,我们首先先来看看什么是编辑距离

编辑距离

我们首先想到的是算法导论上关于编辑距离的定义,但是在此之前我们先看看wikipedia上面的描述:

In computer science, edit distance is a way of quantifying how dissimilar two strings (e.g., words) are to one another by counting the minimum number of operations required to transform one string into the other. Edit distances find applications in natural language processing, where automatic spelling correction can determine candidate corrections for a misspelled word by selecting words from a dictionary that have a low distance to the word in question. Inbioinformatics, it can be used to quantify the similarity of macromolecules such as DNA, which can be viewed as strings of the letters A, C, G and T.


Given two strings a and b on an alphabet Σ (e.g. the set of ASCII characters, the set of bytes [0..255], etc.), the edit distance d(a, b) is the minimum-weight series of edit operations that transforms a into b. One of the simplest sets of edit operations is that defined by Levenshtein in 1966:

Insertion of a single symbol. If a = uv, then inserting the symbol x produces uxv. This can also be denoted ε→x, using ε to denote the empty string.
Deletion of a single symbol changes uxv to uv (x→ε).
Substitution of a single symbol x for a symbol y ≠ x changes uxv to uyv (xy).

由于这个是一道跟字符串有关的题目,按照LeetCode传统的思路就是按字符比较。
我们再看看wikipedia上面的一个例子(是关于了是否有substitution的例子)

The Levenshtein distance between "kitten" and "sitting" is 3. The minimal edit script that transforms the former into the latter is:

  1. kitten → sitten (substitution of "s" for "k")
  2. sitten → sittin (substitution of "i" for "e")
  3. sittin → sitting (insertion of "g" at the end).

LCS distance(insertions and deletions only) gives a different distance and minimal edit script:

  1. delete k at 0
  2. insert s at 0
  3. delete e at 4
  4. insert i at 4
  5. insert g at 6

for a total cost/distance of 5 operations.


然后我们考虑一下传统DP的解法(算导中的一节,为什么做DP就不详细说)。

DP解法


DP操作建模

对于编辑距离的三个操作来说:
插入举例:X:=ex  VS Y:=exp
前面的两个ex都是相同,则编辑距离不变为0,X没有第三个字符,这里如果我们插入了一个字符即可。

删除举例: X:= exp VS Y:= ex
我故意用了这个例子,也就是说插入和删除是互逆的,就是看我们以谁为对象来看待这个问题。

替代举例: X:= sitten VS Y:=sitting
这里例子的第五个字符需要替代,为什么要替代呢? 因为第四个字符和第六个字符相同(这里就需要用DP,也就是说,需要一个空间来记录之前的比较结果和之后的比较结果)。

DP实现:

考虑了几个例子之后,我们再想一下这三个步骤是同时判断的,还是有先后顺序来判断的?
我们再看看wikipedia里面的基本的算法:
Basic algorithm
Main article: Wagner–Fischer algorithm
Using Levenshtein's original operations, the edit distance between  and is given by , defined by the recurrence


This algorithm can be generalized to handle transpositions by adding an additional term in the recursive clause's minimization

public class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        int[][] dp = new int[len1+1][len2+1];
        
        if(len1 == 0) return len2;
        if(len2 == 0) return len1;
        
        for(int i = 0; i < len1+1; i++)
            dp[i][0] = i;
        for(int i = 0 ; i < len2+1; i++)
            dp[0][i] = i;
        
        for(int i = 1; i < len1+1; i++){
            for(int j = 1 ; j <len2+1;j++){
                //dp[i][j]  VS dp[i][j-1]+1(cost) for delete  VS dp[i-1][j] +1(cost) for insert VS dp[i-1][j-1] + cost for substitution
                int cost = word1.charAt(i-1)==word2.charAt(j-1) ? 0 : 1;
                dp[i][j] = Math.min(dp[i-1][j-1]+cost,Math.min(dp[i][j-1]+1,dp[i-1][j]+1));
                
            }
        }
        return dp[len1][len2];
    }
}



博客参考:
博客查阅:

[leetcode]Edit Distance

代码优化:
进阶学习:



LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值