题目:
给定一个字符串S,请将S分割成一些子串,使每个子串都是回文串,返回S所有可能的分割方案
方法一:回溯+深度优先搜索
1. 主要思想
- 使用 深度优先搜索(DFS) 遍历
s
的所有可能划分方式。 - 使用 回溯(Backtracking)尝试所有可能的子串分割,并在搜索失败时撤销上一步决策。
- 剪枝优化:如果某个子串不是回文,就直接跳过,减少不必要的递归调用。
以 "aab"
为例,我们一步步拆解执行过程:
(1) 递归函数 dfs(i)
dfs(i)
代表从索引i
开始尝试分割s[i:]
。- 终止条件:当
i == n
(遍历完整个字符串),说明找到了一个完整的回文划分,将path
复制到ans
中。
(2) 遍历所有可能的子串
- 设
j
为子串s[i:j+1]
的结束索引:- 如果
s[i:j+1]
是回文,则递归处理s[j+1:]
。 - 如果
s[i:j+1]
不是回文,就跳过这个分割。
- 如果
Step 1: dfs(0)
i = 0
,遍历j
从0
到2
:s[0:1] = "a"
是回文 → 加入path
→dfs(1)
s[0:2] = "aa"
是回文 → 加入path
→dfs(2)
s[0:3] = "aab"
不是回文 → 跳过
Step 2: dfs(1)
(继续从 "a"
后开始)
i = 1
,遍历j
从1
到2
:s[1:2] = "a"
是回文 → 加入path
→dfs(2)
Step 3: dfs(2)
(继续从 "a"
后开始)
i = 2
,遍历j
从2
到2
:s[2:3] = "b"
是回文 → 加入path
→dfs(3)
Step 4: dfs(3)
(终止条件)
i = 3 == len(s)
,找到一个完整的划分["a", "a", "b"]
,存入ans
,然后回溯。
4. 回溯过程
- 回溯到
dfs(2)
,撤销"b"
,继续找其他可能(没有)。 - 回溯到
dfs(1)
,撤销"a"
,尝试"aa"
:"aa"
是回文 →dfs(2)
- 继续拆分
s[2:3] = "b"
,得到["aa", "b"]
,存入ans
。
最终 ans = [["a", "a", "b"], ["aa", "b"]]
。
class Solution(object):
def partition(self, s):
"""
:type s: str
:rtype: List[List[str]]
"""
n=len(s) #字符串的长度
ans=[] #存储所有符合条件的回文子串分割方案
path=[] #存储当前的分割方案,DFS过程中会不断更新
def dfs(i):
if i==n: #被分割完毕
ans.append(path[:]) #复制
return
for j in range(i,n):
t=s[i:j+1] #t是s的子串,索引 i 到 j
if t==t[::-1]: #生成t的逆序,判断是否为回文
path.append(t)#将 t 加入当前分割方案
dfs(j+1)# 递归处理s[j+1:]
path.pop() #回溯
dfs(0)
return ans
时间复杂度:O(n2n),其中 n 为 s 的长度
空间复杂度:O(n)