给你一个字符串 s,请你将 s 分割成一些 子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
示例 1:
输入: s = "aab"
**输出:[["a","a","b"],["aa","b"]]
示例 2:
输入: s = "a"
**输出:[["a"]]
提示:
1 <= s.length <= 16s仅由小写英文字母组成
如果已经在某个位置切了一刀,那么接着只需要考虑这个位置后面的子串怎么切,这就有点"问题与子问题"的意思在了,可以写一个 dfs 函数,dfs(i) 表示字符串 s 未分割的部分是从下标 i 开始到字符串末尾,那么递归终止条件是 i == n
接着再看[i, n - 1]这部分子串,要在哪切?显然必须要从 i 开始往后枚举每个位置,看看这个位置 j 能否与起点 i 构成回文串。如果不行就继续往后枚举;如果可以,那么就将这个回文串加入答案,然后从 j + 1 开始往后找回文串,也就是调用 dfs(j + 1),dfs(j + 1) 返回后,把本次加入答案的结果弹出(因为一直递归调用 dfs 必然能走到 i == n 的时候,此时 path 会被加入到 ans 中),然后继续循环
也就是说,dfs 递归调用控制的是切几刀,递归深度越深,切的刀数就越多,因为一直在前面已经切了的基础上往后切。遍历控制的是在哪切,在当前刀数一定的情况下,往后找分割的位置
python
from typing import List
def partition(s: str) -> List[List[str]]:
ans = []
path = []
n = len(s)
def dfs(i: int) -> None:
# dfs(i) 表示 s 未分割的部分为 [i,n - 1]
if i == n:
# 不能用 ans.append("".join(path)),否则无法 pop
ans.append(path.copy())
return
# 枚举终点
for j in range(i, n):
substr = s[i: j + 1] # 把子串分割出来
if substr == substr[::-1]:
# 如果是回文串
path.append(substr)
dfs(j + 1) # 从当前回文串的终点的后一个位置开始往后找新的串
path.pop() # 恢复现场
dfs(0)
return ans
def main():
with open("case.txt", "r") as f:
ss = f.read().split()
for s in ss:
result = partition(s)
print(f"s = {s}")
print(result)
print()
if __name__ == "__main__":
main()