This commit is contained in:
krahets
2023-07-16 04:19:01 +08:00
parent 54b99d13c8
commit dbf682ebc9
110 changed files with 25308 additions and 10305 deletions

View File

@ -25,7 +25,7 @@
<title>12.3.   子集和问题 - Hello 算法</title>
<title>13.3.   子集和问题 - Hello 算法</title>
@ -79,7 +79,7 @@
<div data-md-component="skip">
<a href="#123" class="md-skip">
<a href="#133" class="md-skip">
跳转至
</a>
@ -113,7 +113,7 @@
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
12.3. &nbsp; 子集和问题
13.3. &nbsp; 子集和问题
</span>
</div>
@ -1752,6 +1752,87 @@
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_13" >
<div class="md-nav__link md-nav__link--index ">
<a href="../../chapter_divide_and_conquer/">12. &nbsp; &nbsp; 分治</a>
<label for="__nav_13">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_13_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_13">
<span class="md-nav__icon md-icon"></span>
12. &nbsp; &nbsp; 分治
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../chapter_divide_and_conquer/divide_and_conquer/" class="md-nav__link">
12.1. &nbsp; 分治算法New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_divide_and_conquer/build_binary_tree/" class="md-nav__link">
12.2. &nbsp; 构建树问题New
</a>
</li>
</ul>
</nav>
</li>
@ -1761,7 +1842,7 @@
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_13" checked>
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_14" checked>
@ -1784,18 +1865,18 @@
<div class="md-nav__link md-nav__link--index ">
<a href="../">12. &nbsp; &nbsp; 回溯</a>
<a href="../">13. &nbsp; &nbsp; 回溯</a>
<label for="__nav_13">
<label for="__nav_14">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_13_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_13">
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_14_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_14">
<span class="md-nav__icon md-icon"></span>
12. &nbsp; &nbsp; 回溯
13. &nbsp; &nbsp; 回溯
</label>
<ul class="md-nav__list" data-md-scrollfix>
@ -1808,7 +1889,7 @@
<li class="md-nav__item">
<a href="../backtracking_algorithm/" class="md-nav__link">
12.1. &nbsp; 回溯算法
13.1. &nbsp; 回溯算法
</a>
</li>
@ -1822,7 +1903,7 @@
<li class="md-nav__item">
<a href="../permutations_problem/" class="md-nav__link">
12.2. &nbsp; 全排列问题
13.2. &nbsp; 全排列问题
</a>
</li>
@ -1845,12 +1926,12 @@
<label class="md-nav__link md-nav__link--active" for="__toc">
12.3. &nbsp; 子集和问题
13.3. &nbsp; 子集和问题
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
12.3. &nbsp; 子集和问题
13.3. &nbsp; 子集和问题
</a>
@ -1869,22 +1950,22 @@
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#1231" class="md-nav__link">
12.3.1. &nbsp; 从全排列引出解法
<a href="#1331" class="md-nav__link">
13.3.1. &nbsp; 从全排列引出解法
</a>
</li>
<li class="md-nav__item">
<a href="#1232" class="md-nav__link">
12.3.2. &nbsp; 重复子集剪枝
<a href="#1332" class="md-nav__link">
13.3.2. &nbsp; 重复子集剪枝
</a>
</li>
<li class="md-nav__item">
<a href="#1233" class="md-nav__link">
12.3.3. &nbsp; 相等元素剪枝
<a href="#1333" class="md-nav__link">
13.3.3. &nbsp; 相等元素剪枝
</a>
</li>
@ -1905,7 +1986,7 @@
<li class="md-nav__item">
<a href="../n_queens_problem/" class="md-nav__link">
12.4. &nbsp; N 皇后问题
13.4. &nbsp; N 皇后问题
</a>
</li>
@ -1919,168 +2000,7 @@
<li class="md-nav__item">
<a href="../summary/" class="md-nav__link">
12.5. &nbsp; 小结
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_14" >
<div class="md-nav__link md-nav__link--index ">
<a href="../../chapter_dynamic_programming/">13. &nbsp; &nbsp; 动态规划</a>
<label for="__nav_14">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_14_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_14">
<span class="md-nav__icon md-icon"></span>
13. &nbsp; &nbsp; 动态规划
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/intro_to_dynamic_programming/" class="md-nav__link">
13.1. &nbsp; 初探动态规划New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/dp_problem_features/" class="md-nav__link">
13.2. &nbsp; DP 问题特性New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/dp_solution_pipeline/" class="md-nav__link">
13.3. &nbsp; DP 解题思路New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/knapsack_problem/" class="md-nav__link">
13.4. &nbsp; 0-1 背包问题New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/unbounded_knapsack_problem/" class="md-nav__link">
13.5. &nbsp; 完全背包问题New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/edit_distance_problem/" class="md-nav__link">
13.6. &nbsp; 编辑距离问题New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/summary/" class="md-nav__link">
13.7. &nbsp; 小结New
13.5. &nbsp; 小结
</a>
</li>
@ -2111,31 +2031,53 @@
<label class="md-nav__link" for="__nav_15" id="__nav_15_label" tabindex="0">
14. &nbsp; &nbsp; 附录
<span class="md-nav__icon md-icon"></span>
</label>
<div class="md-nav__link md-nav__link--index ">
<a href="../../chapter_dynamic_programming/">14. &nbsp; &nbsp; 动态规划</a>
<label for="__nav_15">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_15_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_15">
<span class="md-nav__icon md-icon"></span>
14. &nbsp; &nbsp; 附录
14. &nbsp; &nbsp; 动态规划
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../chapter_appendix/installation/" class="md-nav__link">
14.1. &nbsp; 编程环境安装
<a href="../../chapter_dynamic_programming/intro_to_dynamic_programming/" class="md-nav__link">
14.1. &nbsp; 初探动态规划New
</a>
</li>
@ -2148,8 +2090,78 @@
<li class="md-nav__item">
<a href="../../chapter_appendix/contribution/" class="md-nav__link">
14.2. &nbsp; 一起参与创作
<a href="../../chapter_dynamic_programming/dp_problem_features/" class="md-nav__link">
14.2. &nbsp; DP 问题特性New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/dp_solution_pipeline/" class="md-nav__link">
14.3. &nbsp; DP 解题思路New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/knapsack_problem/" class="md-nav__link">
14.4. &nbsp; 0-1 背包问题New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/unbounded_knapsack_problem/" class="md-nav__link">
14.5. &nbsp; 完全背包问题New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/edit_distance_problem/" class="md-nav__link">
14.6. &nbsp; 编辑距离问题New
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_dynamic_programming/summary/" class="md-nav__link">
14.7. &nbsp; 小结New
</a>
</li>
@ -2180,6 +2192,75 @@
<label class="md-nav__link" for="__nav_16" id="__nav_16_label" tabindex="0">
15. &nbsp; &nbsp; 附录
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_16_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_16">
<span class="md-nav__icon md-icon"></span>
15. &nbsp; &nbsp; 附录
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../chapter_appendix/installation/" class="md-nav__link">
15.1. &nbsp; 编程环境安装
</a>
</li>
<li class="md-nav__item">
<a href="../../chapter_appendix/contribution/" class="md-nav__link">
15.2. &nbsp; 一起参与创作
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_17" >
@ -2192,8 +2273,8 @@
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_16_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_16">
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_17_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_17">
<span class="md-nav__icon md-icon"></span>
参考文献
</label>
@ -2234,22 +2315,22 @@
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#1231" class="md-nav__link">
12.3.1. &nbsp; 从全排列引出解法
<a href="#1331" class="md-nav__link">
13.3.1. &nbsp; 从全排列引出解法
</a>
</li>
<li class="md-nav__item">
<a href="#1232" class="md-nav__link">
12.3.2. &nbsp; 重复子集剪枝
<a href="#1332" class="md-nav__link">
13.3.2. &nbsp; 重复子集剪枝
</a>
</li>
<li class="md-nav__item">
<a href="#1233" class="md-nav__link">
12.3.3. &nbsp; 相等元素剪枝
<a href="#1333" class="md-nav__link">
13.3.3. &nbsp; 相等元素剪枝
</a>
</li>
@ -2277,13 +2358,13 @@
<h1 id="123">12.3. &nbsp; 子集和问题<a class="headerlink" href="#123" title="Permanent link">&para;</a></h1>
<h1 id="133">13.3. &nbsp; 子集和问题<a class="headerlink" href="#133" title="Permanent link">&para;</a></h1>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>给定一个正整数数组 <code>nums</code> 和一个目标正整数 <code>target</code> ,请找出所有可能的组合,使得组合中的元素和等于 <code>target</code> 。给定数组无重复元素,每个元素可以被选取多次。请以列表形式返回这些组合,列表中不应包含重复组合。</p>
</div>
<p>例如,输入集合 <span class="arithmatex">\(\{3, 4, 5\}\)</span> 和目标整数 <span class="arithmatex">\(9\)</span> ,由于集合中的数字可以被重复选取,因此解为 <span class="arithmatex">\(\{3, 3, 3\}, \{4, 5\}\)</span> 。请注意,子集是不区分元素顺序的,例如 <span class="arithmatex">\(\{4, 5\}\)</span><span class="arithmatex">\(\{5, 4\}\)</span> 是同一个子集。</p>
<h2 id="1231">12.3.1. &nbsp; 从全排列引出解法<a class="headerlink" href="#1231" title="Permanent link">&para;</a></h2>
<h2 id="1331">13.3.1. &nbsp; 从全排列引出解法<a class="headerlink" href="#1331" title="Permanent link">&para;</a></h2>
<p>类似于上节全排列问题的解法,我们可以把子集的生成过程想象成一系列选择的结果,并在选择过程中实时更新“元素和”,当元素和等于 <code>target</code> 时,就将子集记录至结果列表。</p>
<p>而与全排列问题不同的是,本题允许重复选取同一元素,因此无需借助 <code>selected</code> 布尔列表来记录元素是否已被选择。我们可以对全排列代码进行小幅修改,初步得到解题代码。</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:11"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Java</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Python</label><label for="__tabbed_1_4">Go</label><label for="__tabbed_1_5">JavaScript</label><label for="__tabbed_1_6">TypeScript</label><label for="__tabbed_1_7">C</label><label for="__tabbed_1_8">C#</label><label for="__tabbed_1_9">Swift</label><label for="__tabbed_1_10">Zig</label><label for="__tabbed_1_11">Dart</label></div>
@ -2524,7 +2605,7 @@
<p><img alt="子集搜索与越界剪枝" src="../subset_sum_problem.assets/subset_sum_i_naive.png" /></p>
<p align="center"> Fig. 子集搜索与越界剪枝 </p>
<h2 id="1232">12.3.2. &nbsp; 重复子集剪枝<a class="headerlink" href="#1232" title="Permanent link">&para;</a></h2>
<h2 id="1332">13.3.2. &nbsp; 重复子集剪枝<a class="headerlink" href="#1332" title="Permanent link">&para;</a></h2>
<p>为了去除重复子集,<strong>一种直接的思路是对结果列表进行去重</strong>。但这个方法效率很低,因为:</p>
<ul>
<li>当数组元素较多,尤其是当 <code>target</code> 较大时,搜索过程会产生大量的重复子集。</li>
@ -2794,7 +2875,7 @@
<p><img alt="子集和 I 回溯过程" src="../subset_sum_problem.assets/subset_sum_i.png" /></p>
<p align="center"> Fig. 子集和 I 回溯过程 </p>
<h2 id="1233">12.3.3. &nbsp; 相等元素剪枝<a class="headerlink" href="#1233" title="Permanent link">&para;</a></h2>
<h2 id="1333">13.3.3. &nbsp; 相等元素剪枝<a class="headerlink" href="#1333" title="Permanent link">&para;</a></h2>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>给定一个正整数数组 <code>nums</code> 和一个目标正整数 <code>target</code> ,请找出所有可能的组合,使得组合中的元素和等于 <code>target</code><strong>给定数组可能包含重复元素,每个元素只可被选择一次</strong>。请以列表形式返回这些组合,列表中不应包含重复组合。</p>
@ -3162,7 +3243,7 @@
<nav class="md-footer__inner md-grid" aria-label="页脚" >
<a href="../permutations_problem/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 12.2. &amp;nbsp; 全排列问题" rel="prev">
<a href="../permutations_problem/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 13.2. &amp;nbsp; 全排列问题" rel="prev">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</div>
@ -3171,20 +3252,20 @@
上一页
</span>
<div class="md-ellipsis">
12.2. &nbsp; 全排列问题
13.2. &nbsp; 全排列问题
</div>
</div>
</a>
<a href="../n_queens_problem/" class="md-footer__link md-footer__link--next" aria-label="下一页: 12.4. &amp;nbsp; N 皇后问题" rel="next">
<a href="../n_queens_problem/" class="md-footer__link md-footer__link--next" aria-label="下一页: 13.4. &amp;nbsp; N 皇后问题" rel="next">
<div class="md-footer__title">
<span class="md-footer__direction">
下一页
</span>
<div class="md-ellipsis">
12.4. &nbsp; N 皇后问题
13.4. &nbsp; N 皇后问题
</div>
</div>
<div class="md-footer__button md-icon">