回溯算法总结
`
文章目录
前言
主要借鉴【代码随想录】,大部分为笔记,由于自己学习整理。
一、回溯算法是什么
回溯算法也可叫回溯搜索法,它是⼀种搜索的⽅式;
回溯是递归的副产品,只要有递归就会有回溯。本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法⾼效⼀些,可以加⼀些剪枝的操作,但也改不了回溯法就是穷举的本质。
回溯法解决的问题都可以抽象为树形结构,因为回溯法解决的都是在集合中递归查找⼦集,集合的⼤⼩就构成了树的宽度,递归的深度,都构成的树的深度。
递归就要有终⽌条件,所以必然是⼀颗⾼度有限的树(N叉树)
二、回溯算法主要解决的问题
1)组合问题:N个数⾥⾯按⼀定规则找出k个数的集合
2)切割问题:⼀个字符串按⼀定规则有⼏种切割⽅式
3)⼦集问题:⼀个N个数的集合⾥有多少符合条件的⼦集
4)排列问题:N个数按⼀定规则全排列,有⼏种排列⽅式
5)棋盘问题:N皇后,解数独等等
三、回溯算法三部曲
- 递归函数的返回值以及参数
- 回溯函数终⽌条件
- 单层搜索的过程
四、回溯算法模板
def backtracking(参数):
if (终止条件):
存放结果
return
for (本层集合中元素((树中节点孩⼦的数量就是集合的⼤⼩)):
处理节点
backtracking(路径,选择列表)
回溯,撤销处理结果
五、一些例子
5.1 lc77 组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
ans = []
temp = []
#参数n,k,还有startIndex,用于记录从哪里开始遍历,题目是任意顺序
#即在集合[1,2,3,4]取1之后,下⼀层递归,就要在[2,3,4]中取数了,那么下⼀
#层递归如何知道从[2,3,4]中取数呢,靠的就是startIndex。
def backtrack(n, k, startIndex):
if len(temp) == k:
ans.append(temp[:])
return
#for循环选择的起始位置之后的元素个数已经不⾜我们需要的元素个数了
#那么就没有必要搜索
for i in range(startIndex, n - (k - len(temp)) + 2):
temp.append(i)
backtrack(n, k, i+1)
temp.pop()
backtrack(n, k, 1)
return ans
剪枝操作:
1、已选的元素个数,len(temp)
2、还需要选的元素个数,k - len(temp)
3、在集合n中,至多要从该起始位置 到n - (k - len(temp)) + 1,开始遍历。·(组合问题)
,上面里面+2是因为边界要+1.
(因为for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了)
5.2 lc216组合总和 III
lc216
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
- 只使用数字1到9
- 每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
ans = []
temp = []
def backtrack(n, k, sum, startIndex):
if sum > n:
return
if len(temp) == k and sum == n:
ans.append(temp[:])
for i in range(startIndex, 9 - (k - len(temp))+2):
sum += i
temp.append(i)
backtrack(n, k, sum, i+1) #使用i+1调整startIndex
temp.pop()
sum -= i
backtrack(n, k, 0, 1)
return ans
5.3 lc17. 电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return list()
phoneMap = {
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz",
}
def backtrack(index: int):
if index == len(digits):
combinations.append("".join(combination))
else:
digit = digits[index]
for letter in phoneMap[digit]:
combination.append(letter)
backtrack(index + 1)
combination.pop()
combination = list()
combinations = list()
backtrack(0)
return combinations