72. 编辑距离(动态规划)

    科技2022-07-14  144

    题目

    给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

    你可以对一个单词进行如下三种操作:

    插入一个字符删除一个字符替换一个字符

    示例 1:

    输入:word1 = "horse", word2 = "ros" 输出:3 解释: horse -> rorse (将 'h' 替换为 'r') rorse -> rose (删除 'r') rose -> ros (删除 'e')

    示例 2:

    输入:word1 = "intention", word2 = "execution" 输出:5 解释: intention -> inention (删除 't') inention -> enention (将 'i' 替换为 'e') enention -> exention (将 'n' 替换为 'x') exention -> exection (将 'n' 替换为 'c') exection -> execution (插入 'u')

    思路

    做题之前,先了解一下编辑距离的定义(一下来源于百度百科):

    编辑距离(Minimum Edit Distance,MED),由俄罗斯科学家 Vladimir Levenshtein 在1965年提出,也因此而得名 Levenshtein Distance。

    编辑距离 是针对二个字符串(例如英文字)的差异程度的量化量测,量测方式是看至少需要多少次的处理才能将一个字符串变成另一个字符串。编辑距离可以用在自然语言处理中,例如拼写检查可以根据一个拼错的字和其他正确的字的编辑距离,判断哪一个(或哪几个)是比较可能的字。DNA也可以视为用A、C、G和T组成的字符串,因此编辑距离也用在生物信息学中,判断二个DNA的类似程度。Unix下的diff及patch即是利用编辑距离来进行文本编辑对比的例子。

    在整题中,始终要有这样一个理解,假设将 word1 转化为 word2 至少需要 x 步,那么同样的,将 word2 转化为 word1 也至少需要 x 步,并且编辑距离的描述也不是题目描述的那样,我认为正确的描述应该是:word1 和 word2 相互转化最少需要多少步,也即 w o r d 1 → w o r d 2 word1 \rightarrow word2 word1word2 或者 w o r d 2 → w o r d 1 word2 \rightarrow word1 word2word1 至少需要多少步,这样对于不了解编辑距离定义的人来讲,不会产生只考虑 w o r d 1 → w o r d 2 word1 \rightarrow word2 word1word2 的误解;

    下面开始讲正解:

    我们采用动态规划的思想,这个是编辑距离算法所采用的思想,定义一个 dp[i][j] 数组,表示 word1[0:i] 转化为 word2[0:j] 所需要的最少步骤,有了这样的定义,这道题其实就很好理解了,为了方便实现动态规划,我们令 dp[][] = int[len1+1][len2+1] ,这样就能方便处理 word1 为空或者 word2 为空的情况,我们将本体的动态规划状态转移描述如下:

    初始状态,即 word1 或者 word2 为空时,分别对应 dp[0][j] = j 和 dp[i][0] = i;word1[i] == word2[j],这种情况下我们只需考虑 word1[0:i-1] 和 word[0:j-1] 之间的编辑距离,所以有 dp[i][j] = dp[i-1][j-1];word[i] != word[j],这种情况稍微复杂一些,需要分三种情况讨论: 先计算 word1[0:i] 与 word1[0:j-1] 的编辑距离,再令 word1[i+1] = word2[j],这样就实现了 word1 到 word2 的转换;与上述相反的过程,先计算 word1[0:i-1] 与 word1[0:j] 的编辑距离,再令 word1[i] = word2[j+1],这看似是将 word2 转化为 word1 的过程,但实际上如上面所说,word1 和 word2 之间的转化是相互的;先计算 word[0:i-1] 与 word[0:j-1] 之间的编辑距离,对于 word[i] 与 word[j] 我们只需要替换其中之一即可; 所以在这种情况下,dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1];

    具体代码如下:

    代码

    public class Solution { public int minDistance(String word1, String word2) { int len1 = word1.length(), len2 = word2.length(); int[][] dp = new int[len1+1][len2+1]; for (int i=0; i<=len1; i++){ for (int j=0; j<=len2; j++){ if (i == 0){ dp[i][j] = j; // word1为空,只需添加j+1个字符得到word2 } else if (j == 0){ dp[i][j] = i; // word2为空,word1只需删除i+1个字符得到word2 } else if (word1.charAt(i-1) == word2.charAt(j-1)){ dp[i][j] = dp[i-1][j-1]; //word1[i]==word2[j],则只需看word1[0:i-1]如何得到word2[0:j-1] } else { dp[i][j] = 1 + Math.min(Math.min(dp[i][j-1], dp[i-1][j]), dp[i-1][j-1]); //个字符不同,则分三种情况,取最小值 } } } return dp[len1][len2]; } public static void main(String[] args) { Solution solution = new Solution(); String word1 = "intention", word2 = "execution"; System.out.println(solution.minDistance(word1, word2)); } }
    Processed: 0.016, SQL: 8