LeetCode 72 Edit Distance (动态规划 一维空间优化)

177 篇文章 0 订阅
60 篇文章 0 订阅

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

题目链接:https://leetcode.com/problems/edit-distance/

题目分析:经典动态规划问题,设dp[i][j]为第一个字符串到第i个位置,第二个字符串到第j个位置时所需的最小编辑距离,将word1编辑成word2,删除操作对应的转移方程为dp[i][j] = dp[i][j - 1] + 1,相当于不拿word1的第i个和word2的第j个比,直接将word2的第j个删除,增加操作对应的是dp[i][j] = dp[i - 1][j] + 1,相当于直接在i位置放j的最后一个字母,替换操作需要比较当前两个字符是否相同,转移时若末尾不同则dp[i][j]取三种操作的最小值,初始化dp[0][j] = j,dp[i][0] = i

4ms,时间击败94.32%

class Solution {
    
    private int min3(int a, int b, int c) {
        if (a <= b && a <= c) {
            return a;
        }
        if (b <= a && b <= c) {
            return b;
        }
        return c;
    }

    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        int[][] dp = new int[n + 1][m + 1];
        dp[0][0] = 0;
        for (int i = 1; i <= n; i ++) {
            dp[i][0] = i;
        }
        for (int j = 1; j <= m; j ++) {
            dp[0][j] = j;
        }
        for (int i = 1; i <= n; i ++) {
            for (int j = 1; j <= m; j ++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = 1 + min3(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
                }
            }
        }
        return dp[n][m];
    }
}

空间优化成一维的做法

if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
    dp[i][j] = dp[i - 1][j - 1];
} else {
    dp[i][j] = 1 + min3(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}

不难发现dp[i][j]的值只和其上方,左边以及左上的三个值有关,设dp[j]为当word1的前缀长分别为0到n时,其与word2到第j个字符的编辑距离,在每次对i进行循环时,需要更新dp[0]的值,其实是更新dp[i][0]的值,下面解释以下这行语句是如何等价到二维情况的

dp[j] = 1 + min3(dp[j], dp[j - 1], lu);

1. 左边的dp[j]自然就表示dp[i][j]

2. 右边的dp[j],因当前赋值号左边的dp[j]尚未被更新,故其值为i-1阶段算出的dp[j],即dp[i - 1][j]

3. 右边的dp[j - 1],这个很好理解,就是当前行的前一列的值,即dp[i][j - 1]

4. 右边的lu,lu指left up,首先是其初始值为i - 1,因为在边界上dp[i - 1][j - 1]就是dp[i - 1][0],值自然就是i - 1,之后每次更新时,需要先记录当前dp[j]的值,上面有解释,代表的其实是dp[i - 1][j],当j向后迭代到j+1时,当前的lu就是dp[i - 1][(j + 1) - 1]的值,也就是之前存的dp[i - 1][j],因此需要引入一个tmp变量进行滚动更新

综上可得

dp[j] = 1 + min3(dp[j], dp[j - 1], lu);
等价于
dp[i][j] = 1 + min3(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);

5ms,时间击败77.2%(此题数据有增强过)

class Solution {
    
    private int min3(int a, int b, int c) {
        if (a <= b && a <= c) {
            return a;
        }
        if (b <= a && b <= c) {
            return b;
        }
        return c;
    }
    
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        int[] dp = new int[m + 1];
        // init dp[0][0] ~ dp[0][m]
        for (int j = 0; j <= m; j++) {
            dp[j] = j;
        }

        for (int i = 1; i <= n; i++) {
            dp[0] = i;  // dp[i][0] => delete all word1[:i]
            int lu = i - 1; // dp[i - 1][j - 1] (left, up)
            for (int j = 1; j <= m; j++) {
                int tmp = dp[j];
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[j] = lu;
                } else {
                    dp[j] = 1 + min3(dp[j], dp[j - 1], lu);
                }
                lu = tmp;
            }
        }
        return dp[m];
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值