力扣爆刷第81天--动态规划一网打尽字符串删除和回文子串

力扣爆刷第81天–动态规划一网打尽字符串删除和回文子串

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

题目链接:https://leetcode.cn/problems/delete-operation-for-two-strings/description/
思路:求两个字符串经过最少的删除操作,使得两个字符串相等,初始化要格外注意,定义dp[i][j]表示区间word1[0,i]和区间word2[0,j]相等所需要的最少的删除操作,那么如果word1[i]==word2[j]说明不需要删除,直接延续上一个位置,即dp[i][j]=dp[i-1][j-1],如果word1[i] != word2[j],就需要进行删除操作了,但是需要考虑删除word1还是word2,这取决于删除那边所需要的删除操作最少,如"abc"和"abe",c与e不相等,需要从"abc"和"ab"或者"ab"和"abe"中进行选择,即 dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + 1;
初始化也是一个需要考虑的点,当word1="“时,word2=“abc”,那么第一列需要初始化为[0, 1, 2, 3],表示需要进行的删除操作;当word2=”"时,word1=“abc”,那么第一行需要初始化为[0, 1, 2, 3],表示需要进行的删除操作。

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

二、72. 编辑距离

题目链接:https://leetcode.cn/problems/edit-distance/
思路:上一题是只有删除操作,本题确多了插入和替换操作,其实删除和插入是一个操作,如abc与ab可以把c删掉,也可以给ab加上c,这是一个等价操作,但是替换不太一样,如ab和ac,替换操作相比删除操作少了一步,b与c不同,替换的话只需要从dp[i-1][j-1]+1即可。
依然是定义dp[i][j]表示区间word1[0, i]和word2[0, j]相等所需要的最少操作,如果word1[i]==word2[i]那么,当前位置不需要进行操作,延续上一个位置,dp[i][j] = dp[i-1][j-1];如果word1[i] != word2[i],那么需要考虑替换还是删除(插入和删除一个意思),dp[i][j] = Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1])) + 1;

初始化和上一题一样,另外就是一定要手动推导dp数组,来看看是否匹配递推公式,或者没想出来递推公式,要根据定义从手动推导的dp数组的结果中归纳,下面以一个例子举例:
输入:word1 = “horse”, word2 = “ros”
输出:3
dp数组推导过程:
0 1 2 3
1 1 2 3
2 2 1 2
3 2 2 3
4 3 3 2
5 4 4 3
举一个替换的例子,dp[1][1]时,h和r不等,可以考虑替换,从dp[0][0]+1可达到。

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



三、647. 回文子串

题目链接:https://leetcode.cn/problems/palindromic-substrings/
思路:求回文子串的数量,可以使用动态规划或者双指针,先介绍动态规划,如s=abcba,其中s[0]=s[4],如果我们要是知道bcb是回文,那么就可以知道s是回文,这个过程就是一个推导的过程,由此我们可以发现动态规划的dp复用与推导,另外就是如s[1]=s[3],且相距小于等于2,我们也可以推导出是回文,那么定义一个dp[i][j]表示,区间s[i, j]内的字符串是回文子串,且0<=i<len,0<=j<len,那么上面的推导是s[i]==s[j],需要dp[i+1][j-1],也就是行要向下一行,列要向左一行,也就是当前dp[i][j]需要来自左下角的信息,这个决定了遍历顺序,需要从下往上,从左往右,具体如下代码。

class Solution {
   public int countSubstrings(String s) {
       int len = s.length();
        boolean[][] dp = new boolean[len][len];
        int sum = 0;
        for(int i = len-1; i >= 0; i--) {
            for(int j = i; j < len; j++) {
                if(s.charAt(i) == s.charAt(j) && (j-i<=2 || dp[i+1][j-1])) {
                    dp[i][j] = true;
                    sum++;
                }
            }
        }
        return sum;
    }
}


双指针法:有两种类型的回文子串aba和abba,然后遍历计算即可。

class Solution {
   public int countSubstrings(String s) {
       int sum = 0;
       for(int i = 0; i < s.length(); i++) {
           sum += getCount(s, i, i);
           sum += getCount(s, i, i+1);
       }
       return sum;
    }

    int getCount(String s, int i, int j) {
        int sum = 0;
        while(i >= 0 && j < s.length()) {
            if(s.charAt(i) == s.charAt(j)) {
                sum++;
                i--;
                j++;
            }else {
                break;
            }
        }
        return sum;
    }
}


四、516.最长回文子序列

题目链接:https://leetcode.cn/problems/longest-palindromic-subsequence/description/
思路:和上一题回溯类似,状态由左下角推出,相等时 dp[i][j] = dp[i+1][j-1] + 2,不等时dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。
1 2 3 3 4
0 1 2 2 3
0 0 1 1 2
0 0 0 1 1
0 0 0 0 1

class Solution {
    public int longestPalindromeSubseq(String s) {
        int len = s.length();
        int[][] dp = new int[len][len];
        for (int i = 0; i < len; i++) {
            dp[i][i] = 1;
        }
        for (int i = len-1; i >= 0; i--) {
            for (int j = i+1; j < len; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i+1][j-1] + 2;
                }else {
                    dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
                }
            }
        }
        return dp[0][len-1];
    }
}
  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当年拼却醉颜红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值