代码随想录算法训练营day59 || 583. 两个字符串的删除操作,72. 编辑距离

动态规划之子序列,还是为了编辑距离做铺垫 | LeetCode:583.两个字符串的删除操作_哔哩哔哩_bilibili 动态规划终极绝杀! LeetCode:72.编辑距离_哔哩哔哩_bilibili

583. 两个字符串的删除操作

思路:返回使得s与t相同所需要删除的字符数,这道题初始的处理思想就是转换为求s与t的共同子序列的长度,然后返回  s的长度-共同子序列的长度+t的长度-共同子序列的长度  即可。

// 时间复杂度O(n^2)
// 空间复杂度O(n^2)

class Solution {
    public int minDistance(String word1, String word2) {
        // 使得word1相同,那么说明就是找两个字符串中的非连续最长公共序列
        // 并且是两个字符串内的元素都可以删除,与以往在s中找t的递推方程不同
        // 在s中找t是s中必定存在t,且存在若干t内的元素的重复项,且只可以删除s中的元素,因此我们递推时,dp[i][j]需要考虑与t中每一个元素重复的可能
        // 但是仅仅是比较两个字符串中的元素交集,那么每个元素之间的匹配其实应该是唯一的,即s中只会存在一个t,这点在题目中其实是隐晦的,是在经历过s找t才形成的

        int n = word1.length();
        int m = word2.length();
        char[] s1 = word1.toCharArray();
        char[] s2 = word2.toCharArray();
        int[][] dp = new int[n+1][m+1];
        // 默认dp[0][0]就是零

        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                if(s1[i-1] == s2[j-1])
                    dp[i][j] = dp[i-1][j-1]+1;
                else
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
            }
        }

        return (n-dp[n][m])+(m-dp[n][m]);
    }
}

72. 编辑距离

思路:注意理解编辑距离所求解的是使得s与t成为相同字符串所进行的操作次数,删除s的字符,删除t的字符,替换s和t的字符都属于操作了一次。而dp[i][j]与题目意思保持一致,所具备的含义就是s的i位置前与t的j位置前的字符串称为相同字串需要编辑多少次。所以不管是dp[i-1][j],dp[i][j-1],dp[i-1][j-1]都是属于对s或者t进行了一次编辑。

其次对于序列题目,暴力的思路都是两个字符串内字符一一比较,所以字符串题目的关键就是两个任意位置的字符进行比较。所以在字符题,用动态规划求解的话,发生转移的条件就是判断s[i]与t[j]的相等或不相等。

本题dp[i-1][j],dp[i][j-1]都是删除操作,dp[i-1][j-1]与dp[i][j]而言是替换操作;因为这个替换体现在dp[i][j]会得到dp[i-1][j-1]+1,即我默认通过替换一个元素使得s[i]与t[j]相等了,那么自然转移到的前一状态就是dp[i-1][j-1]。其次对于增加操作,可以等效于在另一者上执行删除,这点需要多理解,我存在的疑惑就是如果可以采用删除来替换增加的话,那么是否会影响之后的元素的判断。

// 时间复杂度O(n^2)
// 空间复杂度O(n^2)

class Solution {
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        char[] w1 = word1.toCharArray();
        char[] w2 = word2.toCharArray();
        int[][] dp = new int[n+1][m+1];

        // 初始化,初始化是针对一方是空串,因此所进行的操作是删除,赋值的内容就是删除的元素
        for(int i=0; i<=n; i++)
            dp[i][0] = i;
    
        for(int j=0; j<=m; j++)
            dp[0][j] = j;

        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                if(w1[i-1] == w2[j-1])
                    dp[i][j] = dp[i-1][j-1];    // w1与w2中出现相同的元素,则无需进行处理
                if(w1[i-1] != w2[j-1])
                    dp[i][j] = Math.min(Math.min(dp[i-1][j-1], dp[i-1][j]), dp[i][j-1])+1;      // dp[i-1][j]是删除  dp[i][j-1]是增加,相当于重新遍历当前j的位置,所以加1
            }
        }

        return dp[n][m];

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值