LeetCode583、两个字符串的删除操作

题目描述

https://leetcode-cn.com/problems/delete-operation-for-two-strings/
在这里插入图片描述

解法

递归(自顶向下动态规划)

class Solution {
    
    
// 备忘录,消除重叠子问题
int[][] memo;
    public int minDistance(String word1, String word2) {
    
    
        int m = word1.length(), n = word2.length();
        // 备忘录值为 -1 代表未曾计算
        memo = new int[m][n];
        for (int[] row : memo) 
            Arrays.fill(row, -1);
        // 计算 s1[0..] 和 s2[0..] 的 lcs 长度
        return dp(word1, 0, word2, 0);
    }

// 递归函数,自顶向下的递推,其问题的定义:计算 s1[i..] 和 s2[j..] 的最少步数
int dp(String s1, int i, String s2, int j) {
    
    
    if (i == s1.length() ){
    
    
        return s2.length()-j;
    }
    if(j == s2.length()) {
    
    
        return s1.length()-i;//全部删除,此时s2为“”,则需要把s1全删除
    }
    // 如果之前计算过,则直接返回备忘录中的答案
    if (memo[i][j] != -1) {
    
    
        return memo[i][j];
    }
    // 根据 s1[i] 和 s2[j] 的情况做选择
    if (s1.charAt(i) == s2.charAt(j)) {
    
    
        memo[i][j] = dp(s1, i + 1, s2, j + 1);
    } else {
    
    
        memo[i][j] = Math.min(
            dp(s1, i + 1, s2, j)+1,//只需删除1个
            dp(s1, i, s2, j + 1)+1//只需删除1个
            //两个都删除的情况被包含在上面
        );
    }
    return memo[i][j];
}

}

在这里插入图片描述

动态规划(自底向上)

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        int m = word1.length(), n = word2.length();
        //使用自顶向下和自底向上的dp数组定义方向相反
        int[][]dp = new int[m+1][n+1];//表示使得s[0,m-1]和s[0,n-1]相同的最少步数

        //边界条件:dp[0][n+1]和dp[m+1][0]表示有一个字符串是空串,则直接将另外一个全删除
        for(int i=0;i<=m;i++){
    
    
            dp[i][0] = i;
        }
        for(int i=0;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];
                }else dp[i][j] = Math.min(
                    dp[i-1][j]+1,
                    dp[i][j-1]+1
                );
            }
        }
        return dp[m][n];
      
    }

}

在这里插入图片描述

上面的动态规划里面,递推只与相邻的几个变量有关,我们可使用状态压缩来优化空间复杂度。

可以参考官方题解:
https://leetcode-cn.com/problems/delete-operation-for-two-strings/solution/liang-ge-zi-fu-chuan-de-shan-chu-cao-zuo-by-leetco/

换个角度上思考:
题目让我们计算将两个字符串变得相同的最少删除次数,最后这两个字符串会被删成什么样子?删除得到的结果不就是它俩的最长公共子序列嘛!

那么,要计算删除的次数,就可以通过最长公共子序列的长度推导出来:

int minDistance(String s1, String s2) {
    
    
    int m = s1.length(), n = s2.length();
    // 复用前文计算 最长公共子序长度的函数
    int lcs = longestCommonSubsequence(s1, s2);
    return m - lcs + n - lcs;
}

猜你喜欢

转载自blog.csdn.net/qq_44861675/article/details/114480892