This commit is contained in:
krahets
2023-12-28 17:18:44 +08:00
parent 5e0d7327db
commit b8a5bd790b
114 changed files with 860 additions and 863 deletions
@@ -1719,7 +1719,7 @@
<span class="md-ellipsis">
8.3 &nbsp; Top-K 问题
8.3 &nbsp; Top-k 问题
</span>
@@ -3966,13 +3966,13 @@
</div>
</div>
</div>
<p>在最差情况下,需要遍历整个物品列表,<strong>因此时间复杂度为 <span class="arithmatex">\(O(n)\)</span></strong> ,其中 <span class="arithmatex">\(n\)</span> 为物品数量。</p>
<p>除排序之外,在最差情况下,需要遍历整个物品列表,<strong>因此时间复杂度为 <span class="arithmatex">\(O(n)\)</span></strong> ,其中 <span class="arithmatex">\(n\)</span> 为物品数量。</p>
<p>由于初始化了一个 <code>Item</code> 对象列表,<strong>因此空间复杂度为 <span class="arithmatex">\(O(n)\)</span></strong></p>
<h3 id="3">3. &nbsp; 正确性证明<a class="headerlink" href="#3" title="Permanent link">&para;</a></h3>
<p>采用反证法。假设物品 <span class="arithmatex">\(x\)</span> 是单位价值最高的物品,使用某算法求得最大价值为 <code>res</code> ,但该解中不包含物品 <span class="arithmatex">\(x\)</span></p>
<p>现在从背包中拿出单位重量的任意物品,并替换为单位重量的物品 <span class="arithmatex">\(x\)</span> 。由于物品 <span class="arithmatex">\(x\)</span> 的单位价值最高,因此替换后的总价值一定大于 <code>res</code><strong>这与 <code>res</code> 是最优解矛盾,说明最优解中必须包含物品 <span class="arithmatex">\(x\)</span></strong></p>
<p>对于该解中的其他物品,我们也可以构建出上述矛盾。总而言之,<strong>单位价值更大的物品总是更优选择</strong>,这说明贪心策略是有效的。</p>
<p>如图 15-6 所示,如果将物品重量和物品单位价值分别看作一张二维图表的横轴和纵轴,则分数背包问题可转化为“求在有限横轴区间下的最大围成面积”。这个类比可以帮助我们从几何角度理解贪心策略的有效性。</p>
<p>如图 15-6 所示,如果将物品重量和物品单位价值分别看作一张二维图表的横轴和纵轴,则分数背包问题可转化为“求在有限横轴区间下围成的最大面积”。这个类比可以帮助我们从几何角度理解贪心策略的有效性。</p>
<p><a class="glightbox" href="../fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="分数背包问题的几何表示" class="animation-figure" src="../fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png" /></a></p>
<p align="center"> 图 15-6 &nbsp; 分数背包问题的几何表示 </p>
+16 -15
View File
@@ -1719,7 +1719,7 @@
<span class="md-ellipsis">
8.3 &nbsp; Top-K 问题
8.3 &nbsp; Top-k 问题
</span>
@@ -3125,7 +3125,7 @@
<li class="md-nav__item">
<a href="#1511" class="md-nav__link">
<span class="md-ellipsis">
15.1.1 &nbsp; 贪心的优点与局限性
15.1.1 &nbsp; 贪心算法的优点与局限性
</span>
</a>
@@ -3143,7 +3143,7 @@
<li class="md-nav__item">
<a href="#1513" class="md-nav__link">
<span class="md-ellipsis">
15.1.3 &nbsp; 贪心解题步骤
15.1.3 &nbsp; 贪心算法解题步骤
</span>
</a>
@@ -3152,7 +3152,7 @@
<li class="md-nav__item">
<a href="#1514" class="md-nav__link">
<span class="md-ellipsis">
15.1.4 &nbsp; 贪心典型例题
15.1.4 &nbsp; 贪心算法典型例题
</span>
</a>
@@ -3481,7 +3481,7 @@
<li class="md-nav__item">
<a href="#1511" class="md-nav__link">
<span class="md-ellipsis">
15.1.1 &nbsp; 贪心的优点与局限性
15.1.1 &nbsp; 贪心算法的优点与局限性
</span>
</a>
@@ -3499,7 +3499,7 @@
<li class="md-nav__item">
<a href="#1513" class="md-nav__link">
<span class="md-ellipsis">
15.1.3 &nbsp; 贪心解题步骤
15.1.3 &nbsp; 贪心算法解题步骤
</span>
</a>
@@ -3508,7 +3508,7 @@
<li class="md-nav__item">
<a href="#1514" class="md-nav__link">
<span class="md-ellipsis">
15.1.4 &nbsp; 贪心典型例题
15.1.4 &nbsp; 贪心算法典型例题
</span>
</a>
@@ -3560,13 +3560,13 @@
<p>我们先通过例题“零钱兑换”了解贪心算法的工作原理。这道题已经在“完全背包问题”章节中介绍过,相信你对它并不陌生。</p>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>给定 <span class="arithmatex">\(n\)</span> 种硬币,第 <span class="arithmatex">\(i\)</span> 种硬币的面值为 <span class="arithmatex">\(coins[i - 1]\)</span> ,目标金额为 <span class="arithmatex">\(amt\)</span> ,每种硬币可以重复选取,问能够凑出目标金额的最少硬币数量。如果无法凑出目标金额则返回 <span class="arithmatex">\(-1\)</span></p>
<p>给定 <span class="arithmatex">\(n\)</span> 种硬币,第 <span class="arithmatex">\(i\)</span> 种硬币的面值为 <span class="arithmatex">\(coins[i - 1]\)</span> ,目标金额为 <span class="arithmatex">\(amt\)</span> ,每种硬币可以重复选取,问能够凑出目标金额的最少硬币数量。如果无法凑出目标金额则返回 <span class="arithmatex">\(-1\)</span></p>
</div>
<p>本题采取的贪心策略如图 15-1 所示。给定目标金额,<strong>我们贪心地选择不大于且最接近它的硬币</strong>,不断循环该步骤,直至凑出目标金额为止。</p>
<p><a class="glightbox" href="../greedy_algorithm.assets/coin_change_greedy_strategy.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="零钱兑换的贪心策略" class="animation-figure" src="../greedy_algorithm.assets/coin_change_greedy_strategy.png" /></a></p>
<p align="center"> 图 15-1 &nbsp; 零钱兑换的贪心策略 </p>
<p>实现代码如下所示。你可能会不由地发出感叹:So clean !贪心算法仅用约十行代码就解决了零钱兑换问题</p>
<p>实现代码如下所示:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:12"><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" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@@ -3811,7 +3811,8 @@
</div>
</div>
</div>
<h2 id="1511">15.1.1 &nbsp; 贪心的优点与局限性<a class="headerlink" href="#1511" title="Permanent link">&para;</a></h2>
<p>你可能会不由地发出感叹:So clean !贪心算法仅用约十行代码就解决了零钱兑换问题。</p>
<h2 id="1511">15.1.1 &nbsp; 贪心算法的优点与局限性<a class="headerlink" href="#1511" title="Permanent link">&para;</a></h2>
<p><strong>贪心算法不仅操作直接、实现简单,而且通常效率也很高</strong>。在以上代码中,记硬币最小面值为 <span class="arithmatex">\(\min(coins)\)</span> ,则贪心选择最多循环 <span class="arithmatex">\(amt / \min(coins)\)</span> 次,时间复杂度为 <span class="arithmatex">\(O(amt / \min(coins))\)</span> 。这比动态规划解法的时间复杂度 <span class="arithmatex">\(O(n \times amt)\)</span> 提升了一个数量级。</p>
<p>然而,<strong>对于某些硬币面值组合,贪心算法并不能找到最优解</strong>。图 15-2 给出了两个示例。</p>
<ul>
@@ -3819,8 +3820,8 @@
<li><strong>反例 <span class="arithmatex">\(coins = [1, 20, 50]\)</span></strong>:假设 <span class="arithmatex">\(amt = 60\)</span> ,贪心算法只能找到 <span class="arithmatex">\(50 + 1 \times 10\)</span> 的兑换组合,共计 <span class="arithmatex">\(11\)</span> 枚硬币,但动态规划可以找到最优解 <span class="arithmatex">\(20 + 20 + 20\)</span> ,仅需 <span class="arithmatex">\(3\)</span> 枚硬币。</li>
<li><strong>反例 <span class="arithmatex">\(coins = [1, 49, 50]\)</span></strong>:假设 <span class="arithmatex">\(amt = 98\)</span> ,贪心算法只能找到 <span class="arithmatex">\(50 + 1 \times 48\)</span> 的兑换组合,共计 <span class="arithmatex">\(49\)</span> 枚硬币,但动态规划可以找到最优解 <span class="arithmatex">\(49 + 49\)</span> ,仅需 <span class="arithmatex">\(2\)</span> 枚硬币。</li>
</ul>
<p><a class="glightbox" href="../greedy_algorithm.assets/coin_change_greedy_vs_dp.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="贪心无法找出最优解的示例" class="animation-figure" src="../greedy_algorithm.assets/coin_change_greedy_vs_dp.png" /></a></p>
<p align="center"> 图 15-2 &nbsp; 贪心无法找出最优解的示例 </p>
<p><a class="glightbox" href="../greedy_algorithm.assets/coin_change_greedy_vs_dp.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="贪心算法无法找出最优解的示例" class="animation-figure" src="../greedy_algorithm.assets/coin_change_greedy_vs_dp.png" /></a></p>
<p align="center"> 图 15-2 &nbsp; 贪心算法无法找出最优解的示例 </p>
<p>也就是说,对于零钱兑换问题,贪心算法无法保证找到全局最优解,并且有可能找到非常差的解。它更适合用动态规划解决。</p>
<p>一般情况下,贪心算法的适用情况分以下两种。</p>
@@ -3841,9 +3842,9 @@
<div class="admonition quote">
<p class="admonition-title">Quote</p>
<p>有一篇论文给出了一个 <span class="arithmatex">\(O(n^3)\)</span> 时间复杂度的算法,用于判断一个硬币组合能否使用贪心算法找出任意金额的最优解。</p>
<p>Pearson, David. A polynomial-time algorithm for the change-making problem. Operations Research Letters 33.3 (2005): 231-234.</p>
<p>Pearson, D. A polynomial-time algorithm for the change-making problem[J]. Operations Research Letters, 2005, 33(3): 231-234.</p>
</div>
<h2 id="1513">15.1.3 &nbsp; 贪心解题步骤<a class="headerlink" href="#1513" title="Permanent link">&para;</a></h2>
<h2 id="1513">15.1.3 &nbsp; 贪心算法解题步骤<a class="headerlink" href="#1513" title="Permanent link">&para;</a></h2>
<p>贪心问题的解决流程大体可分为以下三步。</p>
<ol>
<li><strong>问题分析</strong>:梳理与理解问题特性,包括状态定义、优化目标和约束条件等。这一步在回溯和动态规划中都有涉及。</li>
@@ -3857,7 +3858,7 @@
</ul>
<p>为了保证正确性,我们应该对贪心策略进行严谨的数学证明,<strong>通常需要用到反证法或数学归纳法</strong></p>
<p>然而,正确性证明也很可能不是一件易事。如若没有头绪,我们通常会选择面向测试用例进行代码调试,一步步修改与验证贪心策略。</p>
<h2 id="1514">15.1.4 &nbsp; 贪心典型例题<a class="headerlink" href="#1514" title="Permanent link">&para;</a></h2>
<h2 id="1514">15.1.4 &nbsp; 贪心算法典型例题<a class="headerlink" href="#1514" title="Permanent link">&para;</a></h2>
<p>贪心算法常常应用在满足贪心选择性质和最优子结构的优化问题中,以下列举了一些典型的贪心算法问题。</p>
<ul>
<li><strong>硬币找零问题</strong>:在某些硬币组合下,贪心算法总是可以得到最优解。</li>
+1 -1
View File
@@ -1719,7 +1719,7 @@
<span class="md-ellipsis">
8.3 &nbsp; Top-K 问题
8.3 &nbsp; Top-k 问题
</span>
+14 -14
View File
@@ -1719,7 +1719,7 @@
<span class="md-ellipsis">
8.3 &nbsp; Top-K 问题
8.3 &nbsp; Top-k 问题
</span>
@@ -3562,10 +3562,10 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<p><a class="glightbox" href="../max_capacity_problem.assets/max_capacity_moving_short_board.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="向内移动短板后的状态" class="animation-figure" src="../max_capacity_problem.assets/max_capacity_moving_short_board.png" /></a></p>
<p align="center"> 图 15-10 &nbsp; 向内移动短板后的状态 </p>
<p>由此便可推出本题的贪心策略:初始化两指针分列容器两端,每轮向内收缩短板对应的指针,直至两指针相遇。</p>
<p>由此便可推出本题的贪心策略:初始化两指针,使其分列容器两端,每轮向内收缩短板对应的指针,直至两指针相遇。</p>
<p>图 15-11 展示了贪心策略的执行过程。</p>
<ol>
<li>初始状态下,指针 <span class="arithmatex">\(i\)</span><span class="arithmatex">\(j\)</span> 分列数组两端。</li>
<li>初始状态下,指针 <span class="arithmatex">\(i\)</span><span class="arithmatex">\(j\)</span> 分列数组两端。</li>
<li>计算当前状态的容量 <span class="arithmatex">\(cap[i, j]\)</span> ,并更新最大容量。</li>
<li>比较板 <span class="arithmatex">\(i\)</span> 和 板 <span class="arithmatex">\(j\)</span> 的高度,并将短板向内移动一格。</li>
<li>循环执行第 <code>2.</code> 步和第 <code>3.</code> 步,直至 <span class="arithmatex">\(i\)</span><span class="arithmatex">\(j\)</span> 相遇时结束。</li>
@@ -3611,7 +3611,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.py</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="k">def</span> <span class="nf">max_capacity</span><span class="p">(</span><span class="n">ht</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;最大容量:贪心&quot;&quot;&quot;</span>
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a> <span class="c1"># 初始化 i, j 分列数组两端</span>
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a> <span class="c1"># 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">ht</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a> <span class="c1"># 初始最大容量为 0</span>
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span>
@@ -3631,7 +3631,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.cpp</span><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kt">int</span><span class="w"> </span><span class="nf">maxCapacity</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="o">&amp;</span><span class="n">ht</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ht</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
@@ -3654,7 +3654,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.java</span><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="kt">int</span><span class="w"> </span><span class="nf">maxCapacity</span><span class="p">(</span><span class="kt">int</span><span class="o">[]</span><span class="w"> </span><span class="n">ht</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ht</span><span class="p">.</span><span class="na">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
@@ -3677,7 +3677,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.cs</span><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="kt">int</span><span class="w"> </span><span class="nf">MaxCapacity</span><span class="p">(</span><span class="kt">int</span><span class="p">[]</span><span class="w"> </span><span class="n">ht</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ht</span><span class="p">.</span><span class="n">Length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">;</span>
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">;</span>
@@ -3700,7 +3700,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.go</span><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="kd">func</span><span class="w"> </span><span class="nx">maxCapacity</span><span class="p">(</span><span class="nx">ht</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">ht</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span>
<a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
<a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="w"> </span><span class="nx">res</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span>
@@ -3723,7 +3723,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.swift</span><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="kd">func</span> <span class="nf">maxCapacity</span><span class="p">(</span><span class="n">ht</span><span class="p">:</span> <span class="p">[</span><span class="nb">Int</span><span class="p">])</span> <span class="p">-&gt;</span> <span class="nb">Int</span> <span class="p">{</span>
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a> <span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a> <span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a> <span class="kd">var</span> <span class="nv">i</span> <span class="p">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">j</span> <span class="p">=</span> <span class="n">ht</span><span class="p">.</span><span class="bp">count</span> <span class="o">-</span> <span class="mi">1</span>
<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a> <span class="c1">// 初始最大容量为 0</span>
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a> <span class="kd">var</span> <span class="nv">res</span> <span class="p">=</span> <span class="mi">0</span>
@@ -3746,7 +3746,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.js</span><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="kd">function</span><span class="w"> </span><span class="nx">maxCapacity</span><span class="p">(</span><span class="nx">ht</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span>
<a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">ht</span><span class="p">.</span><span class="nx">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">;</span>
<a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
@@ -3770,7 +3770,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.ts</span><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="kd">function</span><span class="w"> </span><span class="nx">maxCapacity</span><span class="p">(</span><span class="nx">ht</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">[])</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span>
<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">ht</span><span class="p">.</span><span class="nx">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">;</span>
<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
@@ -3794,7 +3794,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.dart</span><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="kt">int</span><span class="w"> </span><span class="n">maxCapacity</span><span class="p">(</span><span class="n">List</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="n">ht</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ht</span><span class="p">.</span><span class="n">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">;</span>
<a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">;</span>
@@ -3817,7 +3817,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.rs</span><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">fn</span> <span class="nf">max_capacity</span><span class="p">(</span><span class="n">ht</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="kt">i32</span><span class="p">])</span><span class="w"> </span>-&gt; <span class="kt">i32</span> <span class="p">{</span>
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ht</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
@@ -3841,7 +3841,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
<div class="tabbed-block">
<div class="highlight"><span class="filename">max_capacity.c</span><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="cm">/* 最大容量:贪心 */</span>
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="kt">int</span><span class="w"> </span><span class="nf">maxCapacity</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">ht</span><span class="p">[],</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">htLength</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j 分列数组两端</span>
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="c1">// 初始化 i, j,使其分列数组两端</span>
<a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">htLength</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="c1">// 初始最大容量为 0</span>
@@ -1719,7 +1719,7 @@
<span class="md-ellipsis">
8.3 &nbsp; Top-K 问题
8.3 &nbsp; Top-k 问题
</span>
@@ -3573,7 +3573,7 @@ n &amp; \geq 4
<ol>
<li>输入整数 <span class="arithmatex">\(n\)</span> ,从其不断地切分出因子 <span class="arithmatex">\(3\)</span> ,直至余数为 <span class="arithmatex">\(0\)</span><span class="arithmatex">\(1\)</span><span class="arithmatex">\(2\)</span></li>
<li>当余数为 <span class="arithmatex">\(0\)</span> 时,代表 <span class="arithmatex">\(n\)</span><span class="arithmatex">\(3\)</span> 的倍数,因此不做任何处理。</li>
<li>当余数为 <span class="arithmatex">\(2\)</span> 时,不继续划分,保留</li>
<li>当余数为 <span class="arithmatex">\(2\)</span> 时,不继续划分,保留。</li>
<li>当余数为 <span class="arithmatex">\(1\)</span> 时,由于 <span class="arithmatex">\(2 \times 2 &gt; 1 \times 3\)</span> ,因此应将最后一个 <span class="arithmatex">\(3\)</span> 替换为 <span class="arithmatex">\(2\)</span></li>
</ol>
<h3 id="2">2. &nbsp; 代码实现<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
+2 -2
View File
@@ -1719,7 +1719,7 @@
<span class="md-ellipsis">
8.3 &nbsp; Top-K 问题
8.3 &nbsp; Top-k 问题
</span>
@@ -3451,7 +3451,7 @@
<li>求解贪心问题主要分为三步:问题分析、确定贪心策略、正确性证明。其中,确定贪心策略是核心步骤,正确性证明往往是难点。</li>
<li>分数背包问题在 0-1 背包的基础上,允许选择物品的一部分,因此可使用贪心算法求解。贪心策略的正确性可以使用反证法来证明。</li>
<li>最大容量问题可使用穷举法求解,时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> 。通过设计贪心策略,每轮向内移动短板,可将时间复杂度优化至 <span class="arithmatex">\(O(n)\)</span></li>
<li>在最大切分乘积问题中,我们先后推理出两个贪心策略:<span class="arithmatex">\(\geq 4\)</span> 的整数都应该继续切分最优切分因子为 <span class="arithmatex">\(3\)</span> 。代码中包含幂运算,时间复杂度取决于幂运算实现方法,通常为 <span class="arithmatex">\(O(1)\)</span><span class="arithmatex">\(O(\log n)\)</span></li>
<li>在最大切分乘积问题中,我们先后推理出两个贪心策略:<span class="arithmatex">\(\geq 4\)</span> 的整数都应该继续切分最优切分因子为 <span class="arithmatex">\(3\)</span> 。代码中包含幂运算,时间复杂度取决于幂运算实现方法,通常为 <span class="arithmatex">\(O(1)\)</span><span class="arithmatex">\(O(\log n)\)</span></li>
</ul>
<!-- Source file information -->