题目链接
分割回文串
题目描述
注意点
- s 仅由小写英文字母组成
- 返回 s 保证每个子串都是回文串所有可能的分割方案
解答思路
- 从左到右将字符串进行分割,分割左侧部分判断是否是回文子串,如果不是说明不满足题意可以忽略;如果是则可以对右侧部分继续进行相同的划分操作,以此递归,直到将整个字符串都分割完成,找到所有满足题意得分割方式。
- 例:将"aabb"进行分割。
- 第一次递归:可将’a’分割出,也可将’aa’分割出来,但是无法将’aab’和’aabb’分割出来(不是回文子串)
- 第二次递归:分割’a’-可将’abb’中的’a’分割出;分割’aa’-可将’bb’中的’b’分割出,也可以将’bb’中的’bb’分割出
- 第三次递归:分割’a’,分割’a’-可将’bb’中的’b’分割出,也可以将’bb’中的’bb’分割出,以此类推…
- 判断某个子串是否是回文子串,可以用一个结构进行存储,判断所有子串是否是回文子串时可以通过动态规划从较短的子串推出较长的子串
代码
class Solution {
public List<List<String>> partition(String s) {
List<List<String>> res = new ArrayList<>();
Deque<String> tmp = new ArrayDeque<>();
int len = s.length();
// dp[i][j]表示[i,j]子串是否是回文子串
boolean[][] dp = new boolean[len][len];
for (int subLen = 0; subLen < len; subLen++) {
for (int left = 0; left + subLen < len; left++) {
int right = left + subLen;
if (s.charAt(left) == s.charAt(right) && ((left + 1) > (right - 1) || dp[left + 1][right - 1])) {
dp[left][right] = true;
}
}
}
findPartition(s, 0, res, tmp, dp);
return res;
}
public void findPartition(String s, int left, List<List<String>> res, Deque<String> tmp, boolean[][] dp) {
for (int subLen = 0; left + subLen < s.length(); subLen++) {
// 截取部分非回文子串,不满足条件
if (!dp[left][left + subLen]) {
continue;
}
tmp.addLast(s.substring(left, left + subLen + 1));
if (left + subLen + 1 == s.length()) {
res.add(new ArrayList<>(tmp));
} else {
findPartition(s, left + subLen + 1, res, tmp, dp);
}
tmp.removeLast();
}
}
}
关键点
- 动态规划的思想
- 子串如何进行分割保证所有情况都判断到了且未重复判断
- 在循环中对临时队列添加子串递归后要将添加的子串移除掉,方便下次循环添加新的子串