mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-05 03:30:30 +08:00
feat: Revised the book (#978)
* Sync recent changes to the revised Word. * Revised the preface chapter * Revised the introduction chapter * Revised the computation complexity chapter * Revised the chapter data structure * Revised the chapter array and linked list * Revised the chapter stack and queue * Revised the chapter hashing * Revised the chapter tree * Revised the chapter heap * Revised the chapter graph * Revised the chapter searching * Reivised the sorting chapter * Revised the divide and conquer chapter * Revised the chapter backtacking * Revised the DP chapter * Revised the greedy chapter * Revised the appendix chapter * Revised the preface chapter doubly * Revised the figures
This commit is contained in:
@@ -9,13 +9,13 @@
|
||||
例如,输入集合 $\{3, 4, 5\}$ 和目标整数 $9$ ,解为 $\{3, 3, 3\}, \{4, 5\}$ 。需要注意以下两点。
|
||||
|
||||
- 输入集合中的元素可以被无限次重复选取。
|
||||
- 子集是不区分元素顺序的,比如 $\{4, 5\}$ 和 $\{5, 4\}$ 是同一个子集。
|
||||
- 子集不区分元素顺序,比如 $\{4, 5\}$ 和 $\{5, 4\}$ 是同一个子集。
|
||||
|
||||
### 参考全排列解法
|
||||
|
||||
类似于全排列问题,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素和”,当元素和等于 `target` 时,就将子集记录至结果列表。
|
||||
|
||||
而与全排列问题不同的是,**本题集合中的元素可以被无限次选取**,因此无须借助 `selected` 布尔列表来记录元素是否已被选择。我们可以对全排列代码进行小幅修改,初步得到解题代码。
|
||||
而与全排列问题不同的是,**本题集合中的元素可以被无限次选取**,因此无须借助 `selected` 布尔列表来记录元素是否已被选择。我们可以对全排列代码进行小幅修改,初步得到解题代码:
|
||||
|
||||
```src
|
||||
[file]{subset_sum_i_naive}-[class]{}-[func]{subset_sum_i_naive}
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
向以上代码输入数组 $[3, 4, 5]$ 和目标元素 $9$ ,输出结果为 $[3, 3, 3], [4, 5], [5, 4]$ 。**虽然成功找出了所有和为 $9$ 的子集,但其中存在重复的子集 $[4, 5]$ 和 $[5, 4]$** 。
|
||||
|
||||
这是因为搜索过程是区分选择顺序的,然而子集不区分选择顺序。如下图所示,先选 $4$ 后选 $5$ 与先选 $5$ 后选 $4$ 是两个不同的分支,但两者对应同一个子集。
|
||||
这是因为搜索过程是区分选择顺序的,然而子集不区分选择顺序。如下图所示,先选 $4$ 后选 $5$ 与先选 $5$ 后选 $4$ 是不同的分支,但对应同一个子集。
|
||||
|
||||

|
||||
|
||||
@@ -37,13 +37,13 @@
|
||||
**我们考虑在搜索过程中通过剪枝进行去重**。观察下图,重复子集是在以不同顺序选择数组元素时产生的,例如以下情况。
|
||||
|
||||
1. 当第一轮和第二轮分别选择 $3$ 和 $4$ 时,会生成包含这两个元素的所有子集,记为 $[3, 4, \dots]$ 。
|
||||
2. 之后,当第一轮选择 $4$ 时,**则第二轮应该跳过 $3$** ,因为该选择产生的子集 $[4, 3, \dots]$ 和 `1.` 中生成的子集完全重复。
|
||||
2. 之后,当第一轮选择 $4$ 时,**则第二轮应该跳过 $3$** ,因为该选择产生的子集 $[4, 3, \dots]$ 和第 `1.` 步中生成的子集完全重复。
|
||||
|
||||
在搜索中,每一层的选择都是从左到右被逐个尝试的,因此越靠右的分支被剪掉的越多。
|
||||
在搜索过程中,每一层的选择都是从左到右被逐个尝试的,因此越靠右的分支被剪掉的越多。
|
||||
|
||||
1. 前两轮选择 $3$ 和 $5$ ,生成子集 $[3, 5, \dots]$ 。
|
||||
2. 前两轮选择 $4$ 和 $5$ ,生成子集 $[4, 5, \dots]$ 。
|
||||
3. 若第一轮选择 $5$ ,**则第二轮应该跳过 $3$ 和 $4$** ,因为子集 $[5, 3, \dots]$ 和 $[5, 4, \dots]$ 与第 `1.` 和 `2.` 步中描述的子集完全重复。
|
||||
3. 若第一轮选择 $5$ ,**则第二轮应该跳过 $3$ 和 $4$** ,因为子集 $[5, 3, \dots]$ 和 $[5, 4, \dots]$ 与第 `1.` 步和第 `2.` 步中描述的子集完全重复。
|
||||
|
||||

|
||||
|
||||
@@ -51,18 +51,18 @@
|
||||
|
||||
### 代码实现
|
||||
|
||||
为实现该剪枝,我们初始化变量 `start` ,用于指示遍历起点。**当做出选择 $x_{i}$ 后,设定下一轮从索引 $i$ 开始遍历**。这样做就可以让选择序列满足 $i_1 \leq i_2 \leq \dots \leq i_m$ ,从而保证子集唯一。
|
||||
为实现该剪枝,我们初始化变量 `start` ,用于指示遍历起始点。**当做出选择 $x_{i}$ 后,设定下一轮从索引 $i$ 开始遍历**。这样做就可以让选择序列满足 $i_1 \leq i_2 \leq \dots \leq i_m$ ,从而保证子集唯一。
|
||||
|
||||
除此之外,我们还对代码进行了以下两项优化。
|
||||
|
||||
- 在开启搜索前,先将数组 `nums` 排序。在遍历所有选择时,**当子集和超过 `target` 时直接结束循环**,因为后边的元素更大,其子集和都一定会超过 `target` 。
|
||||
- 在开启搜索前,先将数组 `nums` 排序。在遍历所有选择时,**当子集和超过 `target` 时直接结束循环**,因为后边的元素更大,其子集和一定超过 `target` 。
|
||||
- 省去元素和变量 `total` ,**通过在 `target` 上执行减法来统计元素和**,当 `target` 等于 $0$ 时记录解。
|
||||
|
||||
```src
|
||||
[file]{subset_sum_i}-[class]{}-[func]{subset_sum_i}
|
||||
```
|
||||
|
||||
如下图所示,为将数组 $[3, 4, 5]$ 和目标元素 $9$ 输入到以上代码后的整体回溯过程。
|
||||
下图所示为将数组 $[3, 4, 5]$ 和目标元素 $9$ 输入以上代码后的整体回溯过程。
|
||||
|
||||

|
||||
|
||||
@@ -80,9 +80,9 @@
|
||||
|
||||
### 相等元素剪枝
|
||||
|
||||
为解决此问题,**我们需要限制相等元素在每一轮中只被选择一次**。实现方式比较巧妙:由于数组是已排序的,因此相等元素都是相邻的。这意味着在某轮选择中,若当前元素与其左边元素相等,则说明它已经被选择过,因此直接跳过当前元素。
|
||||
为解决此问题,**我们需要限制相等元素在每一轮中只能被选择一次**。实现方式比较巧妙:由于数组是已排序的,因此相等元素都是相邻的。这意味着在某轮选择中,若当前元素与其左边元素相等,则说明它已经被选择过,因此直接跳过当前元素。
|
||||
|
||||
与此同时,**本题规定数组中的每个元素只能被选择一次**。幸运的是,我们也可以利用变量 `start` 来满足该约束:当做出选择 $x_{i}$ 后,设定下一轮从索引 $i + 1$ 开始向后遍历。这样即能去除重复子集,也能避免重复选择元素。
|
||||
与此同时,**本题规定每个数组元素只能被选择一次**。幸运的是,我们也可以利用变量 `start` 来满足该约束:当做出选择 $x_{i}$ 后,设定下一轮从索引 $i + 1$ 开始向后遍历。这样既能去除重复子集,也能避免重复选择元素。
|
||||
|
||||
### 代码实现
|
||||
|
||||
|
||||
Reference in New Issue
Block a user