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

209 阅读2分钟

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

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

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

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

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

1.计数

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

2.求最大值最小值

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

3.求存在性

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

leecode 131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

示例 1:

输入:s = "aab"

输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"

输出:[["a"]]

提示:

1 <= s.length <= 16

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的是回文串的验证,还有第二步,将所有可能是回文的字符递归找出来,添加进数组里。😄 😄 😄 ~}

假如字符串为"aba", 我们知道有两种情况:a,a,a 和 aba

简单的讲讲该怎么递归

  1. 每次递归边界为字符的长度,将拆分后的字符添加进结果集数组,并结束该次递归。

  2. 判断是否为回文,因为是回文才符合题意

  3. 当i = 0 时,j = 0,1,2 分别递归加入拆分后的数组中

  4. 这只是一个临时存放一种结果的数组,用完要移除。

参考代码

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考虑边界
                    }
                }
            }
        }
         dfs(s, 0);
            return ret;
    }

    public void dfs(String s, int i) {
        if (i == n) {
            ret.add(new ArrayList<String>(ans));
            return;
        }
        for (int j = i; j < n; ++j) {
            if (dp[i][j]) {
                ans.add(s.substring(i, j + 1));
                dfs(s, j + 1);
                ans.remove(ans.size() - 1);
            }
        }
    }
}




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

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

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