力扣解题思路:72. 编辑距离

72. 编辑距离


思路:修改一个字符串成为另一个字符串,使得修改次数最少。一次修改操作包括:插入一个字符、删除一个字符、替换一个字符。

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')

这一题和这一题 583. 两个字符串的删除操作 类似
只不过区别是这一题是可以替换和插入字符串的,583. 两个字符串的删除操作 我提供了两种动态规划的思路,一种是先算出最长公共子序列的长度,然后返回s1.length() + s2.length() - 2 * lcs(s1, s2, s1.length(), s2.length())即可,另一种方法就是直接一个一个的删除字符。显然这一题我们无法通过第一种方法解题,因为最终的修改次数不满足s1.length() + s2.length() - 2 * lcs(s1, s2, s1.length(), s2.length())的结果,所以我们采用第二种思路。->
首先,我们用dp[i][j]表示的word1的前i个字符与word2的前j个字符达到相同所需的最小修改次数:
(1)当word1.charAt(i-1) == word2.charAt(j-1),我们可以选择不做任何处理,也可以删除、修改、添加字符,只要取其中最小即可:

dp[i][j] = dp[i - 1][j - 1];                
dp[i][j] = Math.min(dp[i][j],Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1);

其中第二行的dp[i - 1][j - 1]表示替换,dp[i][j - 1]表示插入,dp[i - 1][j]表示删除(所有的操作时针对word1而言的),操作完后操作次数在原来的基础上加1.
(2)当word1.charAt(i-1) == word2.charAt(j-1)不成立,我们就不可以不做任何处理,我们可以删除、修改、添加字符,只要取其中最小即可:

dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1;

同样的,我们也需要对dp数组初始化,方法和583. 两个字符串的删除操作(点这里参考一下呀O(∩_∩)O)

    int[][] dp = new int[m + 1][n + 1];
    for (int i = 1; i <= m; i++) {//这一步可以省略(但是我认为有必要加上)
        Arrays.fill(dp[i],Integer.MAX_VALUE);
    }
    for (int i = 1; i <= m; i++) {
        dp[i][0] = i;
    }
    for (int i = 1; i <= n; i++) {
        dp[0][i] = i;
    }

根据更新规则写出完整的更新方式:

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
                dp[i][j] = Math.min(dp[i][j],Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1);//这一步可以省略(但是我认为有必要加上)
            }else{
                dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1;
            }
        }
    }

完整代码如下:

public int minDistance(String word1, String word2) {
    //if (word1 == null || word2 == null) return 0;
    int m = word1.length(), n = word2.length();
    int[][] dp = new int[m + 1][n + 1];
    for (int i = 1; i <= m; i++) {
        Arrays.fill(dp[i],Integer.MAX_VALUE);
    }
    for (int i = 1; i <= m; i++) {
        dp[i][0] = i;
    }
    for (int i = 1; i <= n; i++) {
        dp[0][i] = i;
    }
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
                dp[i][j] = Math.min(dp[i][j],Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1);
            }else{
                dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1;
            }
        }
    }
    return dp[m][n];
}

面试题 01.05. 一次编辑

思路:
在这里插入图片描述
这一题也可以向上面的方法做,但是上面的方法需要两层循环,我们的题目所给的条件实际上编辑距离不能大于1,那么可以这样:

    public boolean oneEditAway(String first, String second) {
        int len = first.length()-second.length();
        if (len>1||len<-1) {
            return false;
        }
        int count=1;
        for (int i = 0,j=0; i < first.length()&&j < second.length(); i++,j++) {
            if (first.charAt(i)!=second.charAt(j)) {
                if (len==1) { //second要不要添加一个字符
                    j--;
                }else if (len==-1) { //second要不要删除一个字符
                    i--;
                }
                count--;
            }
            if (count<0) {//最多编辑一次
                return false;
            }
        }
        return true;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值