理论知识
回溯法也可以叫做回溯搜索法,它是一种搜索的方式。回溯算法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯会容易很多。
回溯法一般可以解决如下几种问题:
- 组合问题:N个数里面按一定规则找出K个数的集合
- 切割问题:一个字符串按一定的规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等
回溯算法模板:
- 回溯函数模板返回值以及参数:回溯算法中返回值一般为空,参数更具后续的逻辑来,先写逻辑,再写参数,需要什么参数就填什么参数
- 回溯终止条件:存放结果
- 回溯的遍历过程:处理节点, for(调用自己, 回溯(递归),撤销处理结果)。for为横向遍历,递归为纵向遍历
77.组合
思路:
定义两个全局变量res(结果集合),path(单一结果)
1.回溯函数模板返回值以及参数:集合n里面取k个数,startindex参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,…,n] ),startIndex 就是防止出现重复的组合。
2.回溯终止条件:path大小如果达到k,说明找到了一个子集大小为k的组合了,path存的就是根节点到叶子节点的路径,此时用res把path([1,2],[1,3],…保存起来,并终止本层递归。
3.回溯的遍历过程:for循环每次从startIndex开始遍历,然后用path保存取到的节点i。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
path = []
def backtrack(n, k, startIndex):
if len(path) == k:
res.append(path[:])
return
for i in range(startIndex, n+1):
path.append(i)
backtrack(n, k, i+1)
path.pop()
backtrack(n,k,1)
return res
剪枝
可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
path = []
def backtrack(n, k, startIndex):
if len(path) == k:
res.append(path[:])
return
for i in range(startIndex, n-(k-len(path))+2):
path.append(i)
backtrack(n, k, i+1)
path.pop()
backtrack(n,k,1)
return res