一. 题目

二. 思路

1. 迭代加深

  • 隔板是每段的结尾。

  • 迭代加深枚举的隔板数量。

  • 然后dfs,直到选出所有隔板。

  • 中间可以剪枝,当前隔板是否合法。

  • 特殊处理:第一块隔板是0开头;最后一块隔板不在字符串末尾,则最后一段是最后隔板位置+1~s.length-1。

  • 判断回文:字符串哈希、DP、枚举。

2. 朴素dfs

  • 从当前位置枚举合法的终点隔板,直到当前位置越界。

三. 代码

1. 迭代加深

/*
    迭代加深+枚举隔板
    隔板是每个分割字符串的末尾字符
 */
class Solution
{
    static final int N = 20;
    int[] path = new int[N];//隔板
    final List<List<String>> ans = new ArrayList<>();
    final List<String> temp = new ArrayList<>();
    boolean[][] f = new boolean[N][N];

    void init(String s)
    {
        ans.clear();
        for (int i = 0; i < N; ++i)
            Arrays.fill(f[i], false);

        int n = s.length();
        for (int len = 1; len <= n; ++len)//或者字符串哈希判断回文
            for (int l = 0; l + len - 1 < n; ++l)
                if (len == 1) f[l][l] = true;
                else if (len == 2 && s.charAt(l) == s.charAt(l + 1)) f[l][l + 1] = true;
                else if (len > 2)
                {
                    int r = l + len - 1;
                    f[l][r] = s.charAt(l) == s.charAt(r) && f[l + 1][r - 1];
                }
    }

    void dfs(int u, int cnt, int pre, String s)
    {
        if (u == cnt)
        {
            for (int i = 0; i < cnt; ++i)
                if (i == 0) temp.add(s.substring(0, path[0] + 1));
                else temp.add(s.substring(path[i - 1] + 1, path[i] + 1));
            if (path[cnt - 1] != s.length() - 1) temp.add(s.substring(path[cnt - 1] + 1));
            ans.add(new ArrayList<>(temp));
            temp.clear();
            return;
        }

        for (int i = pre + 1; i < s.length(); ++i)//从上一个位置+1开始选当前隔板
        {
            path[u] = i;
            if (u == 0 && !f[0][path[0]]) continue;//剪枝
            if (u != 0 && !f[path[u - 1] + 1][path[u]]) continue;
            if (u == cnt - 1 && i != s.length() - 1 && !f[i + 1][s.length() - 1]) continue;
            dfs(u + 1, cnt, i, s);
        }
    }

    public List<List<String>> partition(String s)
    {
        init(s);
        for (int i = 0; i < s.length(); ++i)
            dfs(0, i + 1, -1, s);
        return ans.stream().distinct().toList();
    }
}

2. 朴素dfs

class Solution
{
    static final int N = 20;
    final List<List<String>> ans = new ArrayList<>();
    final List<String> temp = new ArrayList<>();
    boolean[][] f = new boolean[N][N];

    void init(String s)
    {
        ans.clear();
        for (int i = 0; i < N; ++i)
            Arrays.fill(f[i], false);

        int n = s.length();
        for (int len = 1; len <= n; ++len)//或者字符串哈希判断回文
            for (int l = 0; l + len - 1 < n; ++l)
                if (len == 1) f[l][l] = true;
                else if (len == 2 && s.charAt(l) == s.charAt(l + 1)) f[l][l + 1] = true;
                else if (len > 2)
                {
                    int r = l + len - 1;
                    f[l][r] = s.charAt(l) == s.charAt(r) && f[l + 1][r - 1];
                }
    }

    void dfs(int cur, String s)
    {
        if (cur == s.length())
        {
            ans.add(new ArrayList<>(temp));
            return;
        }

        for (int i = cur; i < s.length(); ++i)
            if (f[cur][i])
            {
                temp.add(s.substring(cur, i + 1));
                dfs(i + 1, s);
                temp.remove(temp.size() - 1);
            }
    }

    public List<List<String>> partition(String s)
    {
        init(s);
        dfs(0, s);
        return ans;
    }
}