力扣第131题-分割回文串

169 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

前言

力扣第131题 分割回文串 如下所示:

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

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

示例 1:

输入: s = "aab"
输出: [["a","a","b"],["aa","b"]]

示例 2:

输入: s = "a"
输出: [["a"]]

一、思路

题目的意思很明确,就是将字符串 s 分割为很多子串,保证每个子串都是 回文串。返回 s 所有可能的分割方案。

题目的难点就在于如何确定分割字符串的位置呢?一个朴素的想法就是:通过递归来逐个分解字符,但是这样需要对每次分割出来的子串都要判定是否为 回文串,只有在碰到子串为回文串的情况下,才会继续向下一层递归。

可以发现我们递归钟最难的就是需寻找下一个回文子串在什么位置,以确定如何分割字符串 s。其实要想知道某个位置 i ~ j 是否为回文串?这个问题就是经典的 动态规划题目 了。可以使用 动态规划 很轻松来确定所有回文子串的位置。

动态规划的本质就是将大问题化解为小问题,从而大大降低时间复杂度。在这一题使用动态规划的时候要注意填表格的顺序:从下往上

综上所述,这一题的大致步骤如下:

  1. 使用 动态规划 确定 i~j 是否为 回文串( -1< i =< j < len)
  2. 使用 递归 深度遍历字符串 s,在分割到字符串最后一位时收集结果即可

递归时为了避免回头,我们用 current 表示当前分割的起始位置,初始值为 0

二、实现

实现代码

实现代码与思路中完全保持一致

boolean[][] flag;
List<List<String>> ret = new ArrayList<>();

public List<List<String>> partition(String s) {
    int len = s.length();
    flag = new boolean[len][len];
    for (int i = len - 1; i >= 0; i--)
    {
        for (int j = i; j < len; ++j)
        {
            if (i == j) // 对角线
                flag[i][j] = true;
            else if (j == i + 1)
                flag[i][j] = s.charAt(i) == s.charAt(j);
            else
                flag[i][j] = s.charAt(i) == s.charAt(j) && flag[i + 1][j - 1];//s[i]是否等于s[j] && 小区间是否为回文串
        }
    }

    dfs(s, 0, new Stack<>());
    return ret;
}

public void dfs(String s, int current, Stack<String> tempRet) {
    int len = s.length();
    if (current == len) {
        // 收集结果
        ret.add(new ArrayList<>(tempRet));
        return;
    }
    for (int j = current; j < len; ++j) {
        if (flag[current][j]) {
            tempRet.push(s.substring(current, j + 1));
            dfs(s, j + 1, tempRet);
            tempRet.pop();
        }
    }
}

测试代码

public static void main(String[] args) {
    String str = "aab";
    new Number131().partition(str);
}

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~