题干
LeetCode链接:https://leetcode-cn.com/explore/interview/card/top-interview-quesitons-in-2018/275/string/1137/
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]
分析
考虑回溯法,即深度优先算法(DFS),把一条路径遍历完,然后回到最近的上一个节点继续遍历,直到把所有可能遍历完。
举例说明:
aabb
- a|abb
1.1 a|a|bb
1.1.1 a|a|b|b 收录
1.1.2 a|a|bb| 收录
1.2 a|ab|b 不是回文串跳过 - aa|bb
2.1 aa|b|b 收录
2.2 aa|bb| 收录 - aab|b 不是回文串跳过
- aabb| 收录
图解如下
/**
* res 是最后结果
* s 是带切割判断的字符串
* tmp 是待加入结果的回文字符串数组
*/
private void backtrack(List<List<String>> res, String s, ArrayList<String> tmp) {
// 如果该字符串已经是空串,表示该路径已经遍历完成
// 则把之前收录的回文字符串数组加入结果
if (s == null || s.length() == 0){
res.add(new ArrayList<>(tmp));
}
// i代表分割线
// 注意:i最大值是s.length()而不是s.length()-1
// 因为分割线可以割到最后空串,即 aabb|
for(int i = 1; i <=s.length();i++){
String left = s.substring(0,i)
// 如果分割后的左侧字符串是回文,才可以继续
if(isPalidrome(left)){
// 收录左边的回文字符串
tmp.add(left);
// 右边剩下的字符串继续分割判断
backtrack(res, s.substring(i, s.length()), tmp);
// 若某条路径已经遍历完,则删除最后一组回文字符串
// 返回到上一节点继续遍历
tmp.remove(tmp.size()-1);
}
}
接下来就是补全回文字符串的判断:
详见:https://blog.csdn.net/weixin_45387738/article/details/102477670
private boolean isPalidrome(String s){
int left = 0;
int right = s.length()-1;
while(left <right){
if(s.charAt(left) != s.charAt(right)){
return false;
}
left ++;
right ++;
}
return true;
}
代码实现
完整代码如下:
class Solution {
public List<List<String>> partition(String s) {
List<List<String>> res = new ArrayList<>();
backtrack(res, s, new ArrayList<String>());
return res;
}
/**
* res 是最后结果
* s 是带切割判断的字符串
* tmp 是待加入结果的回文字符串数组
*/
private void backtrack(List<List<String>> res, String s, ArrayList<String> tmp) {
// 如果该字符串已经是空串,表示该路径已经遍历完成
// 则把之前收录的回文字符串数组加入结果
if (s == null || s.length() == 0){
res.add(new ArrayList<>(tmp));
}
// i代表分割线
// 注意:i最大值是s.length()而不是s.length()-1
// 因为分割线可以割到最后空串,即 aabb|
for(int i = 1; i <=s.length();i++){
String left = s.substring(0,i)
// 如果分割后的左侧字符串是回文,才可以继续
if(isPalidrome(left)){
// 收录左边的回文字符串
tmp.add(left);
// 右边剩下的字符串继续分割判断
backtrack(res, s.substring(i, s.length()), tmp);
// 若某条路径已经遍历完,则删除最后一组回文字符串
// 返回到上一节点继续遍历
tmp.remove(tmp.size()-1);
}
}
private boolean isPalidrome(String s) {
int left = 0;
int right = s.length() - 1;
while (left < right) {
if (s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
}