Skip to content

Latest commit

 

History

History
58 lines (39 loc) · 3.28 KB

backtrack.md

File metadata and controls

58 lines (39 loc) · 3.28 KB

回溯

解题步骤:1.画出树形图。 2.编码。 3.剪枝。

1. 什么时候使用 used 数组,什么时候使用 begin 变量

  • 排序问题,讲究顺序(即 [2, 2, 3] 与 [2, 3, 2] 视为不同列表时),需要记录哪些数字已经使用过,此时用 used 数组;
  • 组合问题,不讲究顺序(即 [2, 2, 3] 与 [2, 3, 2] 视为相同列表时),需要按照某种顺序搜索,此时使用 begin 变量。

使用深度优先遍历有[回头]的过程,在[回头]以后,状态变量需要设置成为和先前一样,因此在回到上一层结点的过程中,需要撤销上一次的选择,这个操作称之为[状态重置];

深度优先遍历,借助系统栈空间,保存所需要的状态变量,在编码中只需要注意遍历到相应的结点的时候,状态变量的值是正确的,具体的做法是:往下走一层的时候,path 变量在尾部追加,而往回走的时候,需要撤销上一次的选择,也是在尾部操作,因此 path 变量是一个栈;

2. 解集不能包含重复的组合,那么如何去掉一个数组中重复的元素?

很容易想到的方案是:先对数组升序排序,重复的元素一定不是排好序以后相同的连续数组区域的第1个元素。

这个避免重复当思想是在是太重要了。 这个方法最重要的作用是,可以让同一层级,不出现相同的元素。即 img.png

为何会有这种神奇的效果呢? 首先 cur-1 == cur 是用于判定当前元素是否和之前元素相同的语句。这个语句就能砍掉例1。 可是问题来了,如果把所有当前与之前一个元素相同的都砍掉,那么例二的情况也会消失。 因为当第二个2出现的时候,他就和前一个2相同了。

那么如何保留例2呢? 那么就用cur > begin 来避免这种情况,你发现例1中的两个2是处在同一个层级上的, 例2的两个2是处在不同层级上的。 在一个for循环中,所有被遍历到的数都是属于一个层级的。我们要让一个层级中, 必须出现且只出现一个2,那么就放过第一个出现重复的2,但不放过后面出现的2。 第一个出现的2的特点就是 cur == begin. 第二个出现的2 特点是cur > begin.

3. 与动态规划的区别

用于求解多阶段决策问题。多阶段决策问题即:

共同点

  • 求解一个问题分为很多步骤(阶段);
  • 每一个步骤(阶段)可以有多种选择。

不同点

  • 动态规划只需要求我们评估最优解是多少,最优解对应的具体解是什么并不要求。因此很适合应用于评估一个方案的效果;
  • 回溯算法可以搜索得到所有的方案(当然包括最优解),但是本质上它是一种遍历算法,时间复杂度很高。

推荐 https://leetcode.cn/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/

例题

46. 全排列 (中等)

47. 全排列 II (中等)

39. 组合总和 (中等)

40. 组合总和 II (中等)

77. 组合 (中等)

78. 子集 (中等)

90. 子集 II (中等)