回溯法,一般可以解决如下几种问题:
组合问题:N个数里面按一定规则找出k个数的集合
切割问题:一个字符串按一定规则有几种切割方式
子集问题:一个N个数的集合里有多少符合条件的子集
排列问题:N个数按一定规则全排列,有几种排列方式
棋盘问题:N皇后,解数独等等
回溯算法可以抽象为一棵树,宽度为每个结点处理的集合的大小(for循环),深度为递归的深度。
模板:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
77. 组合
回溯算法三部曲
题目链接:力扣
思路:回溯
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
path = [] # 当前递归路径上所搜集的元素
res = [] # 结果集二维数组
def backtracking(n, k, startIndex): # ①确定函数参数,startindex确定本次搜索的起始位置
if len(path) == k: # ②确定终止条件
res.append(path[:]) # 列表的深拷贝,注意不能直接res.append(path)
print(path)
return
for i in range(startIndex, n+1): # ③确定中间处理流程
path.append(i)
backtracking(n, k, i+1)
path.pop()
backtracking(n, k, 1)
return res
剪枝:
i 至多等于 n - (k - len(path)) + 1,k-len(path)为还需要多少个元素才满足k,最后还要加1,比如n=5,k=3,此时len(path)为1,i至多从5-(3-1)+1=4开始,因为path还缺2个元素满足k,从5开始就不行了。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
path = [] # 当前递归路径上所搜集的元素
res = [] # 结果集二维数组
def backtracking(n, k, startIndex): # 确定函数参数,startindex确定本次搜索的起始位置
if len(path) == k: # 确定终止条件
res.append(path[:]) # 列表的深拷贝,注意不能直接res.append(path)
print(path)
return
# 剪枝,i至多等于n-(k-len(path))+1,k-len(path)为还需要多少个元素才满足k
for i in range(startIndex, n-(k-len(path))+1 +1):
path.append(i)
backtracking(n, k, i+1)
path.pop()
backtracking(n, k, 1)
return res