【力扣算法】131-分割回文串

题目

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

返回 s 所有可能的分割方案。

示例:

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

题解

暂无官方题解

看到之后,感觉暴力法还是很容易想到的:递归找回文串,然后找到最后就完事了,把一个符合要求的含有String的List压入最后返回的List,然后依次类推回溯找到所有的String List。这样算下来复杂度有 O ( n 3 ) O(n^3 ) O(n3),这个方法肯定可以优化。

自己就去想能不能马拉车优化一下回文串的判断,显然是可以的。马拉车得到辅助数组p[](复杂度 O ( n ) O(n) O(n)),然后利用p[]构造一个’#'之间的回文单向转移图(只会从左向右转移)(复杂度 O ( n 2 ) O(n^2 ) O(n2)),再dfs遍历那个回文单向转移图(复杂度 O ( n 2 ) ​ O(n^2 )​ O(n2)),就可以得到所需的全部字符串List了。

但是这个实现起来,我到dfs那里就不会了。。。Java没有全局变量,然后我自己也不太会Java的数据结构实现,于是就搁置了,看看评论区的大佬。

然后就发现一位用动归+回溯法解决的大佬:(6ms,超过92%,复杂度算下来应该也是 O ( n 2 ) O(n^2 ) O(n2) ? )

//执行用时 : 6 ms, 在Palindrome Partitioning的Java提交中击败了92.79% 的用户
//内存消耗 : 50.5 MB, 在Palindrome Partitioning的Java提交中击败了39.73% 的用户
class Solution {
    int len;
    ArrayList<List<String>> res = new ArrayList<>();
    String s;
    boolean[][] dp;

    public List<List<String>> partition(String s) {
        this.s = s;
        len = s.length();

        if (len < 1)
            return res;

        // dp[i][j] 表示某一子串,s.substring(i, j + 1)
        // 例如 s="babad",dp[0][0] = "b",dp[0][4] = "babad"
        dp = new boolean[len][len];
        // one character
        // 斜着遍历 [0,0] -> [1,1] -> ...
        // 单个字符均为回文
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }
        // two character
        // 斜着遍历 [0,1] -> [1,2] -> ...
        // 两个字符均相同才是回文
        for (int i = 0; i < len - 1; i++) {
            dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1);
        }
        // others
        // 开始dp,  此子串 = 字符 + 左下角的子串 + 字符
        // 只有左下角是回文,同时两端添加的字符相同时,才是回文
        for (int i = 2; i < len; i++) {
            for (int j = 0; j < len - i; j++) {
                dp[j][j + i] = dp[j + 1][j + i - 1] && s.charAt(j) == s.charAt(j + i);
            }
        }
        //回溯法,穿串串
        foo(new LinkedList<>(),0);

        return res;
    }

    void foo(LinkedList<String> path, int level) {
        if (level >= len) {
            res.add(new ArrayList<>(path));
            return;
        }

        for (int i = level; i < len; i++) {
            if (dp[level][i]) {
                path.add(s.substring(level, i + 1));
                foo(path, i + 1);
                path.removeLast();
            }
        }
    }
}

感想

不知道我的思路实现之后大概在什么位置,马拉车应该也算是dp简化了开始的回文判定的部分吧。。。希望能和大佬的6ms成绩不差太多。日后有机会回来实现一下试试。反正其他的评论区答案——那些递归回溯或者dfs回溯的基本都要16ms。还是dp牛逼啊。。。

你可能感兴趣的:(java)