算法思想
1. 回溯法 (Backtracking):
- 回溯法是一种通过递归去尝试所有可能的解,并在每次递归中做出选择、回溯的策略。
- 在这道题中,我们需要通过回溯法来生成字符串的所有可能分割方式,并判断每个分割的子串是否为回文。
2. 分割与判断:
- 首先,我们从字符串的第一个字符开始,依次检查从第一个字符到当前字符构成的子串是否为回文。
- 如果当前子串是回文串,就可以继续尝试从这个子串的结尾位置向后继续分割剩下的部分。
- 如果遍历完所有字符并且成功将字符串分割为回文子串(即字符串遍历完时,所有分割都是回文),就将这种分割方案保存起来。
3. 递归与回溯:
backtrack
方法是递归函数,用来从当前字符开始向后尝试不同的分割方法。- 每次找到一个回文串后,将其加入当前的结果列表 (
currentList
),然后递归处理剩下的部分。 - 当递归到字符串结尾(即
start == s.length()
),说明找到了一种合法的分割方式,这时将当前的分割方式保存到最终结果result
中。 - 当回溯返回时,撤销之前的选择,即将最后加入的回文串从列表中移除 (
currentList.remove(currentList.size() - 1)
),从而继续寻找其他可能的分割方案。
4. 判断回文串:
- 在
isPalindrome
方法中,通过双指针(从字符串两端向中间遍历)来判断某个子串是否是回文。 - 只要发现左右两端字符不相等,就可以确定该子串不是回文,立即返回
false
,否则继续判断直到中间。
代码执行过程(以 "aab" 为例):
- 输入字符串
s = "aab"
。 - 第一次递归从第一个字符开始,先检查子串
"a"
是否为回文,发现是回文,于是将"a"
放入当前的分割列表,然后递归处理剩下的子串"ab"
。 - 在处理
"ab"
时,首先检查"a"
,也是回文,于是继续递归处理"b"
。发现"b"
也是回文,递归结束,得到一种分割方案["a", "a", "b"]
。 - 回溯后,移除最后的
"b"
,然后继续尝试检查"ab"
,发现不是回文,无法进行分割。 - 继续回溯到最外层,移除
"a"
,然后尝试检查前两个字符"aa"
,发现是回文,于是递归处理剩下的"b"
,得到另一种分割方案["aa", "b"]
。 - 递归结束,最终返回所有的分割结果。
复杂度分析:
- 时间复杂度: 最坏情况下,每个子串都可能是回文,所以需要遍历所有可能的分割方式,时间复杂度大致为 O(n * 2^n),其中 n 是字符串的长度。
- 空间复杂度: 由于递归深度取决于字符串的长度,因此空间复杂度为 O(n)。
总结:
这个算法通过回溯法,递归地生成所有可能的子串分割,并通过逐个判断子串是否为回文来过滤合法的分割方案。
java solution
java
class Solution {
public List<List<String>> partition(String s) {
//result包含所有可能的回文分割方案
List<List<String>> result = new ArrayList<>();
//currentList代表某一种可能的回文分割方案
List<String> currentList = new ArrayList<>();
backtrack(result, currentList, s, 0);
return result;
}
private void backtrack(List<List<String>> result, List<String> currentList, String s, int start) {
if(start == s.length()) {
result.add(new ArrayList<>(currentList));
return; //这里必须return,递归终止条件
}
for(int i = start; i < s.length(); ++i) {
if(isPalindrome(s, start, i)) {
currentList.add(s.substring(start, i + 1)); //添加了一个回文子串,currentList.size()增加1
backtrack(result, currentList, s, i + 1);
currentList.remove(currentList.size() - 1); //撤销上个回文子串的选择
}
}
}
private boolean isPalindrome(String s, int low, int high) {
while(low < high) {
if(s.charAt(low) != s.charAt(high)) {
return false;
}
low++;//注意更新左右指针!!
high--;
}
return true;
}
}