【LeetCode 72】 Edit Distance【H】

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

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

  1. 插入一个字符;
  2. 删除一个字符;
  3. 替换一个字符;

在此之前,我们要明确我们的实现思路:将 word2 固定不变,通过改变 word1 来使得 word1 变成 word2。



思路 (DP)

定义:dp[i][j] 为从 word1[0,…,i-1] 转换到 word2[0,…,j-1] 最小的编辑次数。i, j 的起始点从 1 开始。

有了如上的定义之后,我们需要考虑的有2个问题:第一个是 dp[i][j] 的边界问题;第二个问题是 dp[i][j] 的递归表达式。

首先是 dp[i][j] 的边界问题,即将一个非空字符串转换为一个空字符串,需要的最小编辑次数,套用我们之前的定义,就是将 word1[0,…,i-1] 转换为一个空字符串,对应 dp[i][j] 的值是多少,我们有:(作为初始化)

  1. dp[i][0] = i
  2. dp[0][j] = j

接下来我们对第二个问题进行分析:如何得到 dp[i][j] 的递归表达式?
我们如何求得 dp[i][j] 的值?我们利用的是动态规划的思想,即假设我们已经求得 dp[i][j] 之前的所有值(即已知 dp[0,…,i-1][0,…,j-1],并且 word1[0,…,i-2]==word2[0,…,j-2] ),那么我们就可以将问题拆解为一个个相同的小问题:考虑 word1[i-1]word2[j-1]

如果 word1[i-1] == word2[j-1] ,那么相应的 dp[i][j] = dp[i-1][j-1]
如果 word1[i-1] != word2[j-1] ,那么问题变得有些复杂,需要一一分析:(我们需要考虑3种情况)

  1. 替换;需要对 word1[i-1] 进行替换,用 word2[j-1] 来替换 word1[i-1],那么 word1[0,…,i-1] == word2[0,…,j-1] ,此时: dp[i][j] = dp[i - 1][j - 1] + 1
  2. 删除;需要对 word1[i-1] 进行删除,使得 word1[0,…,i-2] == word2[0,…,j-1] ,此时: dp[i][j] = dp[i - 1][j] + 1
  3. 插入;需要将 word2[j-1] 插入到 word1[i-1] 的后面,使得 word1[0,…,i-1] + word2[j-1] == word2[0,…,j-1] ,此时:dp[i][j] = dp[i][j - 1] + 1

最后我们将所有的递归公式写在一起:

  1. dp[i][0] = idp[0][j] = j
  2. 如果 word1[i-1] == word2[j-1]dp[i][j] = dp[i-1][j-1]
  3. 否则 dp[i][j] = min( dp[i][j] = dp[i - 1][j - 1] + 1dp[i][j] = dp[i - 1][j] + 1dp[i][j] = dp[i][j - 1] + 1 )

代码如下:

public class No72 {
    public int minDistance(String word1, String word2) {
        /**
         * DP, 数组 dp[i][j] = x, 指的是 从 word1[0 ~ i-1] 转换到 word2[0 ~ j-1] 所需的最少操作次数(不包括 i, j)
         */
        if (word2.length() == 0) { // 把 word1 中所有字母都删除
            return word1.length();
        }
        if (word1.length() == 0) { // 在 word1 中添加 word2 中的每一个字母
            return word2.length();
        }
        int[][] dp = new int[word1.length()+1][word2.length()+1];
        // 初始化
        for (int i = 0; i <= word1.length(); i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i <= word2.length(); i++) {
            dp[0][i] = i;
        }

        //DP
        for (int i = 1; i <= word1.length(); i++) {
            for (int j = 1; j <= word2.length(); j++) {
                if (word1.charAt(i-1) == word2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    dp[i][j] = Math.min(dp[i-1][j]+1, Math.min(dp[i][j-1]+1, dp[i-1][j-1]+1));
                }
            }
        }

        return dp[word1.length()][word2.length()];
    }
}

参考

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值