Edit Distance

Posted Sheryl Wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Edit Distance相关的知识,希望对你有一定的参考价值。

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

编辑距离,非常经典的二维DP题目,也是传说中的双序列问题。

首先定义最优解的表示,f[i][j]表示将word1前i 个字符转化为word2前j个字符需要的step数目(注意为了方便处理初始值,f[0][0] = 0表示空串的最小编辑距离,之后定义最优解之间的转换状态, 即:

f[i][j] = min(f[i][j-1]+1,f[i-1][j]+1,f[i-1][j-1]) (word1[i-1]==word2[j-1])

f[i][j] = min(f[i][j-1]+1,f[i-1][j]+1,f[i-1][j-1]+1) (word1[i-1]!=word2[j-1])

注意在f[i][j-1],f[i-1][j],f[i-1][j-1]都是可以经过1步或者0步到达f[i][j]的子状态(增加word2[j-1],删除word1[i-1],替换(或者不替换)得到f[i][j]。

这种直接的解法代码如下:

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        if not word1 and not word2:
            return 0
        l1 = len(word1)
        l2 = len(word2)
        res = [[0 for i in xrange(l2+1)] for j in xrange(l1+1)]
        for i in xrange(1,l1+1):
            res[i][0] = i
        for j in xrange(1,l2+1):
            res[0][j] = j
            
        for i in xrange(1,l1+1):
            for j in xrange(1,l2+1):
                res[i][j] = min(res[i-1][j],res[i][j-1])+1
                if word1[i-1] == word2[j-1]:
                    res[i][j] = min(res[i][j],res[i-1][j-1])
                else:
                    res[i][j] = min(res[i][j],res[i-1][j-1]+1)
        return res[l1][l2]

可以发现这种解法时间复杂度是O(mn),空间复杂度也为O(mn),但是实际计算转换状态时,只需要f[i-1][j],f[i][j-1],f[i-1][j-1]三个值,可以使用之前多次使用的滑动数组(滚动数组来解决)。因为在矩阵每一行从左到右处理,所以如果用一个数组res表示处理到j时,res[j-1]已经更新为f[i][j-1],res[j]还没更新为f[i-1][j-1],唯一需要解决的是res[i-1][j-1]。一个好的办法是使用一个单独的变量pre保存res[i-1][j-1]。在每次更新res[j]时先把 res[j]的历史值存储下来,作为下一次更新要使用的f[i-1][j-1]。另外为了减小空间复杂度可以使res为比较短的单词的长度加1,另外上述代码的三次min可以减少为1次min,即提前对f[i-1][j-1]的情况进行处理,代码如下:

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        if not word1 and not word2:
            return 0
        l1 = len(word1)
        l2 = len(word2)
        
        if l1 <= l2: #word1 have the max len
            word1,word2 = word2,word1
            l1,l2 = l2,l1
        res = range(l2+1)
          
        for i in xrange(1,l1+1):
            pre = res[0]
            res[0] = i
            for j in xrange(1,l2+1):
                tmp = res[j]    #缓存f[i-1][j-1]
                if word1[i-1] != word2[j-1]:  #提前处理
                    pre += 1
                res[j] = min(res[j-1]+1,res[j]+1,pre) 
                pre = tmp
                
        return res[l2]
        

 

以上是关于Edit Distance的主要内容,如果未能解决你的问题,请参考以下文章

Minimum Edit Distance with Dynamic Programming

Edit Distance

leetcode第一刷_Edit Distance

LintCode : Edit Distance

LeetCode One Edit Distance

[Locked] One Edit Distance