继续坚持刷题吧,准备刷完题去实习。冲冲冲!!!有好多二叉树的题跳过了,先不刷了。
先丢一个回溯的模版
def backtracking(parameters):
# 终止条件
if termination_condition:
# 存放结果
store_result()
return
# 遍历当前层的选择集合
for choice in choices:
# 处理当前节点
process_choice(choice)
# 递归调用,继续选择
backtracking(path, choice_list)
# 回溯,撤销处理结果
undo_choice(choice)
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
result = []
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if len(path) == k: # path是已经选了的元素
result.append(path[:])
return
for i in range(startIndex, n + 1 ):
path.append(i)
self.backtracking(n, k, i + 1, path, result)
path.pop()
可以进行剪枝,在遍历当前层的选择时可以缩小范围。 就像下面这张图。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
result = []
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if len(path) == k: # path是已经选了的元素
result.append(path[:])
return
for i in range(startIndex, n - (k - len(path)) + 2): # 剪枝只修改了这一行
path.append(i)
self.backtracking(n, k, i + 1, path, result)
path.pop()
总结:见到回溯类的题目要先想到模版,然后先写出来基础版本之后再去考虑是否可以剪枝的问题。加油。
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
result = []
self.backtracking(n, k, 1, [], result)
return result
def backtracking(self, n, k, startIndex, path, result):
if sum(path) > n: # 剪枝操作
return
if sum(path) == n and len(path) == k:
result.append(path[:])
return
for i in range(startIndex, 9 - (k - len(path)) + 2):
path.append(i)
self.backtracking(n, k, i + 1, path, result)
path.pop()
总结:需要做剪枝,不然会TLE,整体和上一题的代码十分类似。只需要在加和大于目标值时直接返回就行。
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return [] # 如果输入为空,直接返回空列表
path = [] # 当前路径存储组合
result = [] # 存储最终结果
hs = {'2':'abc', '3':'def', '4':'ghi', '5':'jkl',
'6':'mno', '7':'pqrs', '8':'tuv', '9':'wxyz'} # 数字到字母映射
# 回溯函数
def backtracking(index):
# 如果当前路径长度等于输入数字的长度,则找到一个组合
if len(path) == len(digits):
result.append(''.join(path)) # 将路径拼成字符串并加入结果
return
# 获取当前数字对应的字母
tmp = hs[digits[index]]
# 遍历每个字母
for i in range(len(tmp)):
path.append(tmp[i]) # 加入当前字母
backtracking(index + 1) # 处理下一个数字
path.pop() # 回溯,移除当前字母
backtracking(0) # 从第一个数字开始回溯
return result
总结:都在注释里了
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
"""
寻找所有可能的组合,使得组合中的数字之和等于目标值 target。
每个数字可以在组合中被重复选取多次。
"""
result = [] # 存储所有满足条件的组合
path = [] # 用于存储当前路径,也就是一个可能的组合
def backtracking(startindex: int):
"""
回溯函数,用于递归地生成所有组合。
:param startindex: 表示开始选择数字的索引,避免重复选择之前已经选择过的数字。
"""
# 如果当前路径中数字的和等于目标值,保存这个组合
if sum(path) == target:
result.append(path[:]) # 深拷贝当前路径并加入结果集
return # 找到一个解之后返回,不再继续递归
# 如果当前路径中数字的和已经超过目标值,提前返回,避免无效递归
if sum(path) > target:
return # 当前组合不符合条件,返回上层调用
# 遍历候选数字,从当前索引开始,防止重复组合
for i in range(startindex, len(candidates)):
path.append(candidates[i]) # 选择当前数字,加入路径
backtracking(i) # 递归地调用回溯函数,允许重复使用当前数字
path.pop() # 回溯:撤销上一步选择,移除当前数字
backtracking(0) # 从索引 0 开始递归查找
return result # 返回所有符合条件的组合