This commit is contained in:
krahets
2023-08-27 23:40:56 +08:00
parent 48980ddf28
commit df0f7d3be1
64 changed files with 255 additions and 261 deletions

View File

@@ -26,7 +26,7 @@ comments: true
输入一个整数数组,数组中不包含重复元素,返回所有可能的排列。
从回溯算法的角度看,**我们可以把生成排列的过程想象成一系列选择的结果**。假设输入数组为 $[1, 2, 3]$ ,如果我们先选择 $1$ 、再选择 $3$ 、最后选择 $2$ ,则获得排列 $[1, 3, 2]$ 。回退表示撤销一个选择,之后继续尝试其他选择。
从回溯算法的角度看,**我们可以把生成排列的过程想象成一系列选择的结果**。假设输入数组为 $[1, 2, 3]$ ,如果我们先选择 $1$、再选择 $3$、最后选择 $2$ ,则获得排列 $[1, 3, 2]$ 。回退表示撤销一个选择,之后继续尝试其他选择。
从回溯代码的角度看,候选集合 `choices` 是输入数组中的所有元素,状态 `state` 是直至目前已被选择的元素。请注意,每个元素只允许被选择一次,**因此 `state` 中的所有元素都应该是唯一的**。
@@ -38,12 +38,12 @@ comments: true
### 1.   重复选择剪枝
为了实现每个元素只被选择一次,我们考虑引入一个布尔型数组 `selected` ,其中 `selected[i]` 表示 `choices[i]` 是否已被选择。剪枝的实现原理为:
为了实现每个元素只被选择一次,我们考虑引入一个布尔型数组 `selected` ,其中 `selected[i]` 表示 `choices[i]` 是否已被选择,并基于它实现以下剪枝操作。
- 在做出选择 `choice[i]` 后,我们就将 `selected[i]` 赋值为 $\text{True}$ ,代表它已被选择。
- 遍历选择列表 `choices` 时,跳过所有已被选择过的节点,即剪枝。
如图 13-6 所示,假设我们第一轮选择 1 ,第二轮选择 3 ,第三轮选择 2 ,则需要在第二轮剪掉元素 1 的分支,在第三轮剪掉元素 1, 3 的分支。
如图 13-6 所示,假设我们第一轮选择 1 ,第二轮选择 3 ,第三轮选择 2 ,则需要在第二轮剪掉元素 1 的分支,在第三轮剪掉元素 1 和元素 3 的分支。
![全排列剪枝示例](permutations_problem.assets/permutations_i_pruning.png)
@@ -907,7 +907,7 @@ comments: true
### 3.   两种剪枝对比
请注意,虽然 `selected` 和 `duplicated` 都用作剪枝,但两者的目标不同
请注意,虽然 `selected` 和 `duplicated` 都用作剪枝,但两者的目标不同的。
- **重复选择剪枝**:整个搜索过程中只有一个 `selected` 。它记录的是当前状态中包含哪些元素,作用是避免某个元素在 `state` 中重复出现。
- **相等元素剪枝**:每轮选择(即每个开启的 `backtrack` 函数)都包含一个 `duplicated` 。它记录的是在遍历中哪些元素已被选择过,作用是保证相等元素只被选择一次。