回溯算法理论基础
回溯法简介
回溯是递归的副产品,只要有递归就会有回溯。回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案。
回溯法解决的问题
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
回溯法解决的问题都可以抽象为树形结构(n叉树)。
77.组合
做题
递归→回溯感觉很简单,但是思路梳理不出来。
看文章
回溯算法关键在于搜索新变量(append)后回溯,要删除新变量(pop)。
未剪枝优化版本如下:
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
self.res = []
self.backtracking(n, k, 1, [])
return self.res
def backtracking(self, n, k, start, path):
if len(path) == k:
self.res.append(path[:])
return
for i in range(start, n+1):
path.append(i)
self.backtracking(n, k, i+1, path)
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:
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() # 回溯,撤销处理的节点
其中,优化的地方“n - (k - len(path)) + 2”应理解为“n + 1 - (k - len(path) + 1)”,即:由“n+1”改为“n+1”减去剩余需要搜索的元素数量(k - len(path) + 1)。
以往忽略的知识点小结
- 回溯算法解决的问题包括组合问题、切割问题、子集问题、排列问题、棋盘问题等,均可抽象为n叉树
- 回溯算法的关键是回溯后删除“新”元素
个人体会
完成时间:50min。
心得:今天是回溯算法的开头,在二叉树的学习基础上,要更深刻去体会回溯算法。