思路:用path 记录,判断边界 什么时候退出dfs,然后for 放内容,path.append(), dfs(下一个) path.pop()恢复现场

python
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
phone = ["","","abc", "def","ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
n=len(digits)
if n==0:
return []
ans = []
path = [''] * n # 注意 path 长度一开始就是 n,不是空列表 最后连起来
def dfs(i):
if i==n:
ans.append(''.join(path))
return
# 枚举每个可能
for c in phone[int(digits[i])]:#
path[i]=c
dfs(i+1)
dfs(0)
return ans

子集回溯形
python
class Solution:
def subsets(self, nums):
# res = [[]]
# for i in nums:
# newSets = []
# for num in res:
# newSets.append([i] + num)
# res = res + newSets
# return res
# dfs
res=[]
n=len(nums)
path=[]
# 选或不选:讨论 nums[i] 是否加入 path
def dfs(i:int )->None:
if i==n:#自己构造完毕
res.append(path[:])
return
# 不选
dfs(i+1)# 考虑下一个数 nums[i+1] 选或不选
# 选
path.append(nums[i])
dfs(i+1)# 考虑下一个数 nums[i+1] 选或不选
path.pop() # 恢复现场,撤销 path.append(nums[i])
dfs(0)
return res



python
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
# 选哪个数字
ans=[]
path=[]
n=len(nums)
def dfs(i):
ans.append(path.copy())
if i==n:
return
for j in range(i,n):
path.append(nums[j])
dfs(j+1)
path.pop()
dfs(0)
return ans


枚举逗号在哪里
python
class Solution:
def partition(self, s: str) -> List[List[str]]:
# 分割子集看是不是会问
ans=[]
path=[]
n=len(s)
def dfs(i):
if i==n:
ans.append(path[:])
return
for j in range(i,n):# 枚举逗号在哪里
t=s[i:j+1]
if t==t[::-1]:
path.append(t)
dfs(j+1)
path.pop()
dfs(0)
return ans;
python
class Solution:
def partition(self, s: str) -> List[List[str]]:
# 选货不选 ,
ans=[]
path=[]
n=len(s)
#现在 s 未被分割的部分为 [start, n-1]
# 当前位于下标 i,讨论是否在 i 和 i+1 之间切一刀
def dfs(i,start):
if i==n:
ans.append(path.copy())
return
# 不分割
if i<n-1:
dfs(i+1,start)
# 分割,那么得到子串 [start, i]
t=s[start:i+1]
if t==t[::-1]:
path.append(t)
# 现在 s 未被分割的部分为 [i+1, n-1]
dfs(i+1,i+1)
path.pop()
dfs(0,0)
return ans

组合型回溯


python
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
# ans=[]
# path=[]
# #枚举下一个数选哪个举选哪个:在 1 到 i 中选一个数,加到 path 末尾
# def dfs(i):
# d=k-len(path)# 还要选 d 个数
# if d==0:#选完了
# ans.append(path.copy())
# return
# # 枚举的数不能太小,否则后面没有数可以选 1,2 1,3
# for j in range(i,d-1,-1):
# path.append(j)
# dfs(j-1)
# path.pop()
# dfs(n) # 从 n 开始倒着枚举
# return ans
# 选货不选
ans=[]
path=[]
#选或不选:讨论 i 是否加入 path
def dfs(i):
d=k-len(path)
if d==0:
ans.append(path.copy())
return
# buxuan i
if i>d:
dfs(i-1)
# xuan i
path.append(i)
dfs(i-1)
path.pop()
dfs(n)
return ans

python
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
ans = []
path = []
def dfs(i: int, left_sum: int) -> None:
d = k - len(path) # 还要选 d 个数
if left_sum < 0 or left_sum > (i * 2 - d + 1) * d // 2: # 剪枝
return
if d == 0: # 找到一个合法组合
ans.append(path.copy())
return
# 枚举的数不能太小,否则后面没有数可以选
for j in range(i, d - 1, -1):
path.append(j)
dfs(j - 1, left_sum - j)
path.pop() # 恢复现场
dfs(9, n) # 从 i=9 开始倒着枚举
return ans



python
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
#对于括号字符串的任意前缀,右括号的个数不能超过左括号的个数
# 选( 还是)
ans=[]
path=['']*(n*2)
m=n*2
def dfs(i,open): #i个括号, open是左括号个数
if i==m:
ans.append(''.join(path))
return
# xuan (
if open<n:
path[i]='('
dfs(i+1,open+1)
if i-open<open: # ) 可以选
path[i]=')'
dfs(i+1,open)
dfs(0,0)
return ans
排列形回溯

python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
# def dfs(x):
# if x == len(nums)-1:
# res.append(list(nums))
# return
# for i in range(x,len(nums)):
# nums[i],nums[x]=nums[x],nums[i] # 交换,将 nums[i] 固定在第 x 位
# dfs(x+1)
# nums[i],nums[x]=nums[x],nums[i] # 恢复交换
# res=[]
# dfs(0)
# return res
# 通用写法
n=len(nums)
path=[0]*n
st=[False]*n #标记每个数字是否被用过
ans=[]
def dfs(x:int)->None:
if x==n:
ans.append(path[:])
return
for i,on in enumerate(st):
if not on:
# 当前i没被用过 放进去path里面标记用过
path[x]=nums[i]
st[i]=True
dfs(x+1)
st[i]=False
dfs(0)
return ans
python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
# 选什么
ans=[]
n=len(nums)
path=[0]*n
vis=[False]*n
# 枚举 path[i] 填 nums 的哪个数
def dfs(i):
if i==n:
ans.append(path.copy())
return
for j in range(len(nums)):
if not vis[j]:# 从没有选的数字中选一个
path[i]=nums[j]
vis[j]=True
dfs(i+1)
vis[j]=False# 恢复现场
# 注意 path 无需恢复现场,因为排列长度固定,直接覆盖就行
dfs(0)
return ans
dfs(0)
