动态规划进阶ing-分割回文串 II|Java 刷题打卡

137 阅读2分钟

本文正在参加「Java主题月 - Java 刷题打卡」,详情查看<活动链接>

【Java 刷题打卡 】刷题比玩游戏好多了,成就感越来越强,每天坚持刷几道题,每天锻炼30分钟,等8块腹肌,等大厂offer.

那就干吧! 这个专栏都是刷的题目都是关于动态规划的,我会由浅入深、循序渐进,刷题就是这样需要连续不断的记忆--艾宾浩斯记忆法2121112。动态规划的内容不多,但是都是每个程序员必备的

这道题很经典啦😄😄😄 \color{green}{这道题很经典啦😄 😄 😄 ~}

什么题可以选择动态规划来做?

1.计数

  • 有多少种方式走到右下角
  • 有多少种方法选出k个数是的和是sum

2.求最大值最小值

  • 从左上角走到右下角路径的最大数字和
  • 最长上升子序列长度

3.求存在性

  • 取石子游戏,先手是否必胜
  • 能不能选出k个数使得和是sum

leecode 132. 分割回文串 II

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。

返回符合要求的 最少分割次数 。

示例 1:

输入:s = "aab"

输出:1

解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。

示例 2:

输入:s = "a"

输出:0

示例 3:

输入:s = "ab"

输出:1

提示:

1 <= s.length <= 2000

s 仅由小写英文字母组成


--

这道题跟前面有道最长回文串右相似之处,可以参考一下~~~ ❤️❤️❤️❤️

2.1. 动态规划组成部分1:确定状态

简单的说,解动态规划的时候需要开一个数组,数组的每个元素f[i]或者f[i][j]代表什么,类似数学题中x, y, z代表什么

最后一步

我们可以同之前的方式判断出所有字符可能组成的字符串。直达

我们用如下示例来讲解,下图是第一步和第二步的判断过程,很明显最后一步为下标为4的字母b与前面所有元素进行比较,得出最长的回文子串。

img

子问题

img

我们可以看到如果f[i] =f[j],要判定它是一个回文串,需要判定

f[i]j] = f[i+1]f[j-1] : 从i到j是一个回文串,那么从i+1到j-1一定也是一个回文串

也就是如上图需要判定a=a

1.2. 动态规划组成部分2:转移方程

对于从i到j长度的字符串,判定它是一个回文串:

f[i]j] = f[i+1]f[j-1]

同时我们也知道,f[i+1][j-1]这是一个已知的,因为最后一步的上一步已经将结果保存,也就是f[i+1][j-1] = f[i+2]f[j-2]

1.3. 动态规划组成部分3:初始条件和边界情况

当剩余判定字母个数<3 并且 f[i] = f[j],它一定是回文串。

对于字母本身来说f[i][i],从i到i的字符串,它也是回文。

1.4. 动态规划组成部分4:计算顺序

如上图,我们用j去匹配0~i (i < j)

当然,这只是对于字符ij的是回文串的验证,还有第二步😄😄😄 \color{green}{当然,这只是对于字符i到j的是回文串的验证,还有第二步😄 😄 😄 ~}

同样正序遍历i和j, 如果f[0][i] = true(是回文)的话不需要分割,否者是需要分割的,我们用i去遍历每个j

如果是回文,我们就记录min{f[i],f[j]+1}

例如字符串:"cdd", 最小1次就行了,在用第二个字母d去遍历c,d,d 三个字符时,在遍历第一个d是回文f[1][2]需要f[2] = 0+1次,遍历第二个d是f[2][2],f[j] + 1 = 2次,所以,会得出min{f[i],f[j]+1}

参考代码

java版

class Solution {
    boolean[][] dp;
    List<List<String>> ret = new ArrayList<List<String>>();
    List<String> ans = new ArrayList<String>();
    int n;

    public List<List<String>> partition(String s) {
        n = s.length();
        dp = new boolean[n][n];
       char[] charArray = s.toCharArray();
        for (int i = 0; i < n; i++) {
            dp[i][i] = true; // 对本身来说就是回文
        }
        for (int j = 1; j < n; j++) {
            for (int i = 0; i < j; i++) {
                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1]; // 要满足这个条件,必需先满足j - i > 3考虑边界
                    }
                }
            }
        }
        int[] f = new int[n];
        Arrays.fill(f, Integer.MAX_VALUE);
        for (int i = 0; i < n; ++i) {
            if (g[0][i]) {
                f[i] = 0;
            } else {
                for (int j = 0; j < i; ++j) {
                    if (g[j + 1][i]) {  // j+ 1的原因是,不用从0开始,我们已经判断了f[0][i]了
                        f[i] = Math.min(f[i], f[j] + 1);  // 这里请看上面说明。
                    }
                }
            }
        }
        return f[n - 1];
    }
    
}




真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话

求点赞👍 求关注❤️ 求分享👥 对8块腹肌的我来说真的 非常有用!!!

如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️