算法训练营第五十九天 | LeetCode 115 不同的子序列、LeetCode 583 两个字符串的删除操作、LeetCode 72 编辑距离

LeetCode 115 不同的子序列


这题和编辑距离比较像,也就是今天的第三题。

这题用动规解决的是多对一的分支子问题推导出当前问题的思路。

同样递推公式由两个字符串平齐,如果当前字符相等,则当前问题可由第一个字符串0~i-1和0~j-1匹配数及0~i-1和j匹配数相加所得;

如果不相等,则直接由0~i-1和j匹配得到。

初始化时,由于第二个字符串如果是0,默认已经匹配,所以dp[i][0]都要初始化为1

代码如下:

class Solution {
    public int numDistinct(String s, String t) {
        int[][] dp = new int[s.length() + 1][t.length() + 1];
        double mod = Math.pow(10, 9) + 7;
        for (int i = 0; i <= s.length(); i++) dp[i][0] = 1;
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); j++) {
                if (s.charAt(i-1) == t.charAt(j-1)) 
                    dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
                else 
                    dp[i][j] = dp[i-1][j];
                if (dp[i][j] > Math.pow(10, 9) + 7) 
                    dp[i][j] %= mod;
            }
        }
        return dp[s.length()][t.length()];
    }
}

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


还是可以转换为最长公共子序列问题

代码如下:

class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];
        int result = 0;
        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]+1;
                else
                    dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]); 
                if (result < dp[i][j]) result = dp[i][j];
            }
        }
        result = word1.length() + word2.length() - result * 2;
        return result;
    }
}

LeetCode 72 编辑距离


这题其实算是用动规来暴力枚举了。dp数组下标含义其实都很好想,就是第一个字符串前i-1个字符和第二个字符串中前j-1个元素的编辑距离。

但是递推公式这一块把我给难住了。我想的是找出一种数学规律,推出递推公式。但其实可以用这么一种解法:

相等时dp[i][j]直接可以由dp[i-1][j-1]推出;

不相等时可以在第一个字符串中删除一个字符, 即dp[i-1][j]+1,

也可以在第一个字符串中插入一个字符,可以视作在第二个字符串中删除一个字符,                    即dp[i][j-1]+1, 

还可以直接替换,即dp[i-1][j-1]+1

这种思考方式其实避免了直接求最长公共子序列再进行操作时部分字符错位的情况,相当于保持了两个字符串开头平齐,从之后开始处理。

遍历顺序自然是从左到右,从上到下了。

初始化方式依照这个逻辑,把dp[i][0]都初始化为i,dp[0][j]都初始化为j就行了。

代码如下:

class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];
        for (int i = 1; i <= word1.length(); i++) dp[i][0] = i;
        for (int j = 1; j <= word2.length(); j++) dp[0][j] = j;
        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],Math.min(dp[i][j-1], dp[i-1][j-1]))+1; 
            }
        }
        return dp[word1.length()][word2.length()];
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值