分割回文串

94 阅读1分钟

题目

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

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

示例:

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

动态规划 + 回溯

import java.util.ArrayList;
import java.util.List;

public class Main {


    public static void main(String[] args) {

        Main main = new Main();
        main.partition("aab");

    }

    String s;
    List<List<String>> ans = new ArrayList<>();
    boolean [][] dpTable;
    public List<List<String>> partition(String s) {
        this.s = s;


        // 首先利用动态规划 得到字符串中哪些字符串能够作为回文串
        dpTable = new boolean[s.length()][s.length()];
        for (int l = 0; l < s.length(); l ++) {
            int left = 0;
            int right = left + l;
            while (right < s.length()) {
                if (l == 0) {
                    dpTable[left][right] = Boolean.TRUE;
                }
                if (l == 1) {
                    dpTable[left][right] = s.charAt(left) == s.charAt(right);
                }
                if ( l > 1) {
                    dpTable[left][right] = dpTable[left + 1][right - 1] && (s.charAt(left) == s.charAt(right));
                }
                left ++;
                right ++;
            }
        }

        // 再利用回溯法得到所有可能的组合
        huisu(new ArrayList<>(), 0);


        return ans;


    }

    public void huisu(List<String> path, int start) {
        if (start == s.length()) {
            List<String> tt = new ArrayList<>();
            tt.addAll(path);
            ans.add(tt);
            return;
        }

        // 选择列表为start开始的所有子串
        for (int i = start; i < s.length(); i ++) {
            if (dpTable[start][i]) {
                // 当前子串是回文才有继续递归下去的必要
                String temp = s.substring(start, i + 1);
                path.add(temp);
                // 注意继续切割字符串的开头, 是现在切割下来字符串的尾巴, 即应该传递i + 1
                huisu(path, i + 1);
                // 撤销选择
                if (path.size() > 0) {
                    path.remove(path.size() - 1);
                }
            }


        }
    }

}

基本思路

  1. 动态规划可以用来判断i, j两个索引在原字符串中的该子串s.subString(i, j + 1)是否是回文串, 提高判断某个已知子串是否是回文的效率

  2. 除非是特殊情况, 否则让你给出所有结果的时候, 回溯法(或者dfs,bfs)是唯一的方法.

  3. 递归的选择是从字符串开头, 按照长度为1开始遍历切割剩下的字符串, 如果切割下来的字符串是回文, 才有继续切割的必要, 递归的条件就是传递起始位置