算法复习-回溯DFS
回溯法,一般可以解决如下几种问题,都可以化成选择树,递归用来纵向遍历,for循环用来横向遍历:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式->转化为组合问题
- 子集问题:一个N个数的集合里有多少符合条件的子集(收集树的所有节点)
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
- 其他分步组合问题
是一种暴力的穷举方法。
模板
注意:for循环外部,每一层函数的递归,代表树的一层(路径长度都为2的子集…) for循环内部代表这一个节点的不同分支
1 | void backtracking(路径, 选择列表) { |
排列/组合子集问题
组合问题和子集问题等价
常用剪枝:
- used数组(排列问题)
- startIndex(组合/子集问题,保证元素 nums[start] 之后只会出现 nums[start+1..] 中的元素,通过固定元素的相对位置保证不出现重复的子集。)
- 子集 II [1,2,2]-> [[],[1],[1,2],[1,2,2],[2],[2,2]]
需要先排序,一个节点有多条值相同的树枝相邻,则只遍历第一条,剩下的都剪掉,不要去遍历.
如果发现 nums[i] == nums[i-1],则跳过(保证同一树层相同元素只会被使用一次)
- 子集 II [1,2,2]-> [[],[1],[1,2],[1,2,2],[2],[2,2]]
- 全排列 II [1,1,2] -> [[1,1,2],[1,2,1],[2,1,1]]
需要先排序,一个节点有多条值相同的树枝相邻,则只遍历第一条,剩下的都剪掉,不要去遍历.
一种剪枝:因为排序之后所有相等的元素都挨在一起,所以只要用 prevNum 记录前一条树枝的值,就可以避免遍历值相同的树枝,从而避免产生相同的子树,最终避免出现重复的排列。
- 全排列 II [1,1,2] -> [[1,1,2],[1,2,1],[2,1,1]]
数独、N皇后
这道题可以认为是数独游戏和 N 皇后问题的简化版:
这道题相当于让你对一个长度为 n 的一维数组中的每一个位置进行穷举,其中每个位置可以填 0 或 1。
数独游戏相当于让你对一个 9x9 的二维数组中的每个位置进行穷举,其中每个位置可以是数字 1~9,且同一行、同一列和同一个 3x3 的九宫格内数字不能重复。
N 皇后问题相当于让你对一个 N x N 的二维数组中的每个位置进行穷举,其中每个位置可以不放皇后或者放置皇后(相当于 0 或 1),且不能存在多个皇后在同一行、同一列或同一对角线上。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 魔法使的后花园!

