模板
回溯算法可以用来解决子集、排列、组合问题,主要形式是从一堆选项中挑选出符合要求的组合,基础模板如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def dining(nums): desk = [] def backtrack(dish, menu): if (满足结束条件): desk.append(dish[:]) for val in menu: dish.append(val) backtrack(dish, 新菜单) dish.pop() backtrack([], nums) return desk
|
解空间结构:常用的有两种,子集树(零一背包问题)和排列树(货郎问题)
- 子集树:从n个元素的集合S中找出满足某种性质的子集时,复杂度 O(2^n)
- 排列树:从n个元素的集合S中找出满足某种性质的排列时,复杂度 O(n!)
应用
子集
LeetCode 78 题
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: desk = [] def trackBack(dish, menu): if (dish not in desk): desk.append(dish[:])
for idx, val in enumerate(menu): dish.append(val) trackBack(dish, menu[(idx+1):]) dish.pop()
trackBack([], nums) return desk
|
组合
LeetCode 77 题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution: def combine(self, n: int, k: int) -> List[List[int]]: desk = [] def backtrack(dish, menu): if (len(dish) == k): desk.append(dish[:]) return
for val in menu: dish.append(val) trackBack(dish, menu[(idx+1):]) dish.pop()
backtrack([], range(1, n + 1)) return desk
|
全排列
LeetCode 46 题
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution: def permute(self, nums: List[int]) -> List[List[int]]: desk = [] long = len(nums) def backtrack(dish, menu): if dish not in desk and len(dish) == long: desk.append(dish[:]) for idx, val in enumerate(menu): dish.append(val) backtrack(dish, menu[:idx] + menu[idx + 1:]) dish.pop() backtrack([], nums) return desk
|
变形
根据不同的题型,回溯算法中变化的部分是结束条件和新菜单。
新菜单指的是,每次可选项的集合,根据不同的题目,新菜单是不一样的。
不包含重复元素的情况
如果解集忽略子项的排序差异,则新菜单为:
1
| newmenu = menu[(idx+1):]
|
如果解集不忽略子项的排序差异 ,则新菜单为:
1
| menu[:idx] + menu[idx + 1:]
|
优化
回溯算法是一种穷举的算法,会遍历所有的情况,我们可以通过剪枝来跳过一些不合符要求的遍历。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def dining(nums): desk = [] def backtrack(dish, menu): if (满足结束条件): desk.append(dish[:]) for val in menu: if (满足剪枝条件): continue dish.append(val) backtrack(dish, 新菜单) dish.pop() backtrack([], nums) return desk
|
练习题
编号为 Leecode 题号
- 全排列(中等)
- 全排列 II(中等
- 组合总和(中等)
- 组合总和 II(中等)
- 组合(中等)
- 子集(中等)
- 子集 II(中等):剪枝技巧同 47 题、39 题、40 题;
- 第 k 个排列(中等)
- 复原 IP 地址(中等)