Polish the content.

This commit is contained in:
krahets
2023-08-21 03:57:09 +08:00
parent f5dda8d99a
commit 1aff6d6cc2
19 changed files with 44 additions and 38 deletions
@@ -128,22 +128,22 @@
**我们考虑在搜索过程中通过剪枝进行去重**。观察下图,重复子集是在以不同顺序选择数组元素时产生的,具体来看:
1. 第一轮和第二轮分别选择 $3$ , $4$ ,会生成包含这两个元素的所有子集,记为 $[3, 4, \cdots]$ 。
2. 若第一轮选择 $4$ ,**则第二轮应该跳过 $3$** ,因为该选择产生的子集 $[4, 3, \cdots]$ 和 `1.` 中生成的子集完全重复。
1. 第一轮和第二轮分别选择 $3$ , $4$ ,会生成包含这两个元素的所有子集,记为 $[3, 4, \dots]$ 。
2. 若第一轮选择 $4$ ,**则第二轮应该跳过 $3$** ,因为该选择产生的子集 $[4, 3, \dots]$ 和 `1.` 中生成的子集完全重复。
分支越靠右,需要排除的分支也越多,例如:
1. 前两轮选择 $3$ , $5$ ,生成子集 $[3, 5, \cdots]$ 。
2. 前两轮选择 $4$ , $5$ ,生成子集 $[4, 5, \cdots]$ 。
3. 若第一轮选择 $5$ ,**则第二轮应该跳过 $3$ 和 $4$** ,因为子集 $[5, 3, \cdots]$ 和子集 $[5, 4, \cdots]$ 和 `1.` , `2.` 中生成的子集完全重复。
1. 前两轮选择 $3$ , $5$ ,生成子集 $[3, 5, \dots]$ 。
2. 前两轮选择 $4$ , $5$ ,生成子集 $[4, 5, \dots]$ 。
3. 若第一轮选择 $5$ ,**则第二轮应该跳过 $3$ 和 $4$** ,因为子集 $[5, 3, \dots]$ 和子集 $[5, 4, \dots]$ 和 `1.` , `2.` 中生成的子集完全重复。
![不同选择顺序导致的重复子集](subset_sum_problem.assets/subset_sum_i_pruning.png)
总结来看,给定输入数组 $[x_1, x_2, \cdots, x_n]$ ,设搜索过程中的选择序列为 $[x_{i_1}, x_{i_2}, \cdots , x_{i_m}]$ ,则该选择序列需要满足 $i_1 \leq i_2 \leq \cdots \leq i_m$ ,**不满足该条件的选择序列都会造成重复,应当剪枝**。
总结来看,给定输入数组 $[x_1, x_2, \dots, x_n]$ ,设搜索过程中的选择序列为 $[x_{i_1}, x_{i_2}, \dots , x_{i_m}]$ ,则该选择序列需要满足 $i_1 \leq i_2 \leq \dots \leq i_m$ ,**不满足该条件的选择序列都会造成重复,应当剪枝**。
### 代码实现
为实现该剪枝,我们初始化变量 `start` ,用于指示遍历起点。**当做出选择 $x_{i}$ 后,设定下一轮从索引 $i$ 开始遍历**。这样做就可以让选择序列满足 $i_1 \leq i_2 \leq \cdots \leq i_m$ ,从而保证子集唯一。
为实现该剪枝,我们初始化变量 `start` ,用于指示遍历起点。**当做出选择 $x_{i}$ 后,设定下一轮从索引 $i$ 开始遍历**。这样做就可以让选择序列满足 $i_1 \leq i_2 \leq \dots \leq i_m$ ,从而保证子集唯一。
除此之外,我们还对代码进行了两项优化: