This commit is contained in:
krahets 2024-05-01 07:30:15 +08:00
parent 85f0bc4ed1
commit d246e08cc6
68 changed files with 220 additions and 220 deletions

View File

@ -3617,7 +3617,7 @@
<p>In this open-source book, however, the content update cycle is shortened to just a few days or even hours.</p>
</div>
<h3 id="1-content-fine-tuning">1. &nbsp; Content fine-tuning<a class="headerlink" href="#1-content-fine-tuning" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 16-3 , there is an "edit icon" in the upper right corner of each page. You can follow these steps to modify text or code.</p>
<p>As shown in Figure 16-3, there is an "edit icon" in the upper right corner of each page. You can follow these steps to modify text or code.</p>
<ol>
<li>Click the "edit icon". If prompted to "fork this repository", please agree to do so.</li>
<li>Modify the Markdown source file content, check the accuracy of the content, and try to keep the formatting consistent.</li>
@ -3626,7 +3626,7 @@
<p><a class="glightbox" href="../contribution.assets/edit_markdown.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Edit page button" class="animation-figure" src="../contribution.assets/edit_markdown.png" /></a></p>
<p align="center"> Figure 16-3 &nbsp; Edit page button </p>
<p>Images cannot be directly modified and require the creation of a new <a href="https://github.com/krahets/hello-algo/issues">Issue</a> or a comment to describe the problem. We will redraw and replace the images as soon as possible.</p>
<p>Figures cannot be directly modified and require the creation of a new <a href="https://github.com/krahets/hello-algo/issues">Issue</a> or a comment to describe the problem. We will redraw and replace the figures as soon as possible.</p>
<h3 id="2-content-creation">2. &nbsp; Content creation<a class="headerlink" href="#2-content-creation" title="Permanent link">&para;</a></h3>
<p>If you are interested in participating in this open-source project, including translating code into other programming languages or expanding article content, then the following Pull Request workflow needs to be implemented.</p>
<ol>

View File

@ -3788,7 +3788,7 @@
<p><a class="glightbox" href="../installation.assets/vscode_installation.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Download VS Code from the official website" class="animation-figure" src="../installation.assets/vscode_installation.png" /></a></p>
<p align="center"> Figure 16-1 &nbsp; Download VS Code from the official website </p>
<p>VS Code has a powerful extension ecosystem, supporting the execution and debugging of most programming languages. For example, after installing the "Python Extension Pack," you can debug Python code. The installation steps are shown in the following figure.</p>
<p>VS Code has a powerful extension ecosystem, supporting the execution and debugging of most programming languages. For example, after installing the "Python Extension Pack," you can debug Python code. The installation steps are shown in Figure 16-2.</p>
<p><a class="glightbox" href="../installation.assets/vscode_extension_installation.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Install VS Code Extension Pack" class="animation-figure" src="../installation.assets/vscode_extension_installation.png" /></a></p>
<p align="center"> Figure 16-2 &nbsp; Install VS Code Extension Pack </p>

View File

@ -3517,7 +3517,7 @@
<!-- Page content -->
<h1 id="163-glossary">16.3 &nbsp; Glossary<a class="headerlink" href="#163-glossary" title="Permanent link">&para;</a></h1>
<p>The Table 16-1 lists the important terms that appear in the book, and it is worth noting the following points.</p>
<p>Table 16-1 lists the important terms that appear in the book, and it is worth noting the following points.</p>
<ul>
<li>It is recommended to remember the English names of the terms to facilitate reading English literature.</li>
<li>Some terms have different names in Simplified and Traditional Chinese.</li>

View File

@ -3747,7 +3747,7 @@
<!-- Page content -->
<h1 id="41-array">4.1 &nbsp; Array<a class="headerlink" href="#41-array" title="Permanent link">&para;</a></h1>
<p>An "array" is a linear data structure that operates as a lineup of similar items, stored together in a computer's memory in contiguous spaces. It's like a sequence that maintains organized storage. Each item in this lineup has its unique 'spot' known as an "index". Please refer to the Figure 4-1 to observe how arrays work and grasp these key terms.</p>
<p>An "array" is a linear data structure that operates as a lineup of similar items, stored together in a computer's memory in contiguous spaces. It's like a sequence that maintains organized storage. Each item in this lineup has its unique 'spot' known as an "index". Please refer to Figure 4-1 to observe how arrays work and grasp these key terms.</p>
<p><a class="glightbox" href="../array.assets/array_definition.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Array definition and storage method" class="animation-figure" src="../array.assets/array_definition.png" /></a></p>
<p align="center"> Figure 4-1 &nbsp; Array definition and storage method </p>
@ -4195,7 +4195,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20insert%28nums%3A%20list%5Bint%5D,%20num%3A%20int,%20index%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%9C%A8%E6%95%B0%E7%BB%84%E7%9A%84%E7%B4%A2%E5%BC%95%20index%20%E5%A4%84%E6%8F%92%E5%85%A5%E5%85%83%E7%B4%A0%20num%22%22%22%0A%20%20%20%20%23%20%E6%8A%8A%E7%B4%A2%E5%BC%95%20index%20%E4%BB%A5%E5%8F%8A%E4%B9%8B%E5%90%8E%E7%9A%84%E6%89%80%E6%9C%89%E5%85%83%E7%B4%A0%E5%90%91%E5%90%8E%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%BD%8D%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201,%20index,%20-1%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20nums%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E5%B0%86%20num%20%E8%B5%8B%E7%BB%99%20index%20%E5%A4%84%E7%9A%84%E5%85%83%E7%B4%A0%0A%20%20%20%20nums%5Bindex%5D%20%3D%20num%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E7%BB%84%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E6%95%B0%E7%BB%84%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E6%8F%92%E5%85%A5%E5%85%83%E7%B4%A0%0A%20%20%20%20insert%28nums,%206,%203%29%0A%20%20%20%20print%28%22%E5%9C%A8%E7%B4%A2%E5%BC%95%203%20%E5%A4%84%E6%8F%92%E5%85%A5%E6%95%B0%E5%AD%97%206%20%EF%BC%8C%E5%BE%97%E5%88%B0%20nums%20%3D%22,%20nums%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<h3 id="4-deleting-elements">4. &nbsp; Deleting elements<a class="headerlink" href="#4-deleting-elements" title="Permanent link">&para;</a></h3>
<p>Similarly, as depicted in the Figure 4-4 , to delete an element at index <span class="arithmatex">\(i\)</span>, all elements following index <span class="arithmatex">\(i\)</span> must be moved forward by one position.</p>
<p>Similarly, as depicted in Figure 4-4, to delete an element at index <span class="arithmatex">\(i\)</span>, all elements following index <span class="arithmatex">\(i\)</span> must be moved forward by one position.</p>
<p><a class="glightbox" href="../array.assets/array_remove_element.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Array element deletion example" class="animation-figure" src="../array.assets/array_remove_element.png" /></a></p>
<p align="center"> Figure 4-4 &nbsp; Array element deletion example </p>

View File

@ -4812,7 +4812,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%93%BE%E8%A1%A8%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%90%8E%E7%BB%A7%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0Adef%20find%28head%3A%20ListNode,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%9C%A8%E9%93%BE%E8%A1%A8%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%80%BC%E4%B8%BA%20target%20%E7%9A%84%E9%A6%96%E4%B8%AA%E8%8A%82%E7%82%B9%22%22%22%0A%20%20%20%20index%20%3D%200%0A%20%20%20%20while%20head%3A%0A%20%20%20%20%20%20%20%20if%20head.val%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20index%0A%20%20%20%20%20%20%20%20head%20%3D%20head.next%0A%20%20%20%20%20%20%20%20index%20%2B%3D%201%0A%20%20%20%20return%20-1%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E9%93%BE%E8%A1%A8%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%84%E4%B8%AA%E8%8A%82%E7%82%B9%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E7%9A%84%E5%BC%95%E7%94%A8%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E6%9F%A5%E6%89%BE%E8%8A%82%E7%82%B9%0A%20%20%20%20index%20%3D%20find%28n0,%202%29%0A%20%20%20%20print%28%22%E9%93%BE%E8%A1%A8%E4%B8%AD%E5%80%BC%E4%B8%BA%202%20%E7%9A%84%E8%8A%82%E7%82%B9%E7%9A%84%E7%B4%A2%E5%BC%95%20%3D%20%7B%7D%22.format%28index%29%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=34&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<h2 id="422-arrays-vs-linked-lists">4.2.2 &nbsp; Arrays vs. linked lists<a class="headerlink" href="#422-arrays-vs-linked-lists" title="Permanent link">&para;</a></h2>
<p>The Table 4-1 summarizes the characteristics of arrays and linked lists, and it also compares their efficiencies in various operations. Because they utilize opposing storage strategies, their respective properties and operational efficiencies exhibit distinct contrasts.</p>
<p>Table 4-1 summarizes the characteristics of arrays and linked lists, and it also compares their efficiencies in various operations. Because they utilize opposing storage strategies, their respective properties and operational efficiencies exhibit distinct contrasts.</p>
<p align="center"> Table 4-1 &nbsp; Efficiency comparison of arrays and linked lists </p>
<div class="center-table">

View File

@ -3659,7 +3659,7 @@
</tbody>
</table>
</div>
<p>We can imagine the computer storage system as a pyramid structure shown in the Figure 4-9 . The storage devices closer to the top of the pyramid are faster, have smaller capacity, and are more costly. This multi-level design is not accidental, but the result of careful consideration by computer scientists and engineers.</p>
<p>We can imagine the computer storage system as a pyramid structure shown in Figure 4-9. The storage devices closer to the top of the pyramid are faster, have smaller capacity, and are more costly. This multi-level design is not accidental, but the result of careful consideration by computer scientists and engineers.</p>
<ul>
<li><strong>Hard disks are difficult to replace with memory</strong>. Firstly, data in memory is lost after power off, making it unsuitable for long-term data storage; secondly, the cost of memory is dozens of times that of hard disks, making it difficult to popularize in the consumer market.</li>
<li><strong>It is difficult for caches to have both large capacity and high speed</strong>. As the capacity of L1, L2, L3 caches gradually increases, their physical size becomes larger, increasing the physical distance from the CPU core, leading to increased data transfer time and higher element access latency. Under current technology, a multi-level cache structure is the best balance between capacity, speed, and cost.</li>
@ -3672,7 +3672,7 @@
<p>The storage hierarchy of computers reflects a delicate balance between speed, capacity, and cost. In fact, this kind of trade-off is common in all industrial fields, requiring us to find the best balance between different advantages and limitations.</p>
</div>
<p>Overall, <strong>hard disks are used for long-term storage of large amounts of data, memory is used for temporary storage of data being processed during program execution, and cache is used to store frequently accessed data and instructions</strong> to improve program execution efficiency. Together, they ensure the efficient operation of computer systems.</p>
<p>As shown in the Figure 4-10 , during program execution, data is read from the hard disk into memory for CPU computation. The cache can be considered a part of the CPU, <strong>smartly loading data from memory</strong> to provide fast data access to the CPU, significantly enhancing program execution efficiency and reducing reliance on slower memory.</p>
<p>As shown in Figure 4-10, during program execution, data is read from the hard disk into memory for CPU computation. The cache can be considered a part of the CPU, <strong>smartly loading data from memory</strong> to provide fast data access to the CPU, significantly enhancing program execution efficiency and reducing reliance on slower memory.</p>
<p><a class="glightbox" href="../ram_and_cache.assets/computer_storage_devices.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Data flow between hard disk, memory, and cache" class="animation-figure" src="../ram_and_cache.assets/computer_storage_devices.png" /></a></p>
<p align="center"> Figure 4-10 &nbsp; Data flow between hard disk, memory, and cache </p>

View File

@ -3621,7 +3621,7 @@
<p>From a garbage collection perspective, for languages with automatic garbage collection mechanisms like Java, Python, and Go, whether node <code>P</code> is collected depends on whether there are still references pointing to it, not on the value of <code>P.next</code>. In languages like C and C++, we need to manually free the node's memory.</p>
<p><strong>Q</strong>: In linked lists, the time complexity for insertion and deletion operations is <code>O(1)</code>. But searching for the element before insertion or deletion takes <code>O(n)</code> time, so why isn't the time complexity <code>O(n)</code>?</p>
<p>If an element is searched first and then deleted, the time complexity is indeed <code>O(n)</code>. However, the <code>O(1)</code> advantage of linked lists in insertion and deletion can be realized in other applications. For example, in the implementation of double-ended queues using linked lists, we maintain pointers always pointing to the head and tail nodes, making each insertion and deletion operation <code>O(1)</code>.</p>
<p><strong>Q</strong>: In the image "Linked List Definition and Storage Method", do the light blue storage nodes occupy a single memory address, or do they share half with the node value?</p>
<p><strong>Q</strong>: In the figure "Linked List Definition and Storage Method", do the light blue storage nodes occupy a single memory address, or do they share half with the node value?</p>
<p>The diagram is just a qualitative representation; quantitative analysis depends on specific situations.</p>
<ul>
<li>Different types of node values occupy different amounts of space, such as int, long, double, and object instances.</li>

View File

@ -4139,7 +4139,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%8F%89%E6%A0%91%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E5%B0%86%E5%88%97%E8%A1%A8%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%BA%E4%BA%8C%E5%8F%89%E6%A0%91%EF%BC%9A%E9%80%92%E5%BD%92%22%22%22%0A%20%20%20%20%23%20%E5%A6%82%E6%9E%9C%E7%B4%A2%E5%BC%95%E8%B6%85%E5%87%BA%E6%95%B0%E7%BB%84%E9%95%BF%E5%BA%A6%EF%BC%8C%E6%88%96%E8%80%85%E5%AF%B9%E5%BA%94%E7%9A%84%E5%85%83%E7%B4%A0%E4%B8%BA%20None%20%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%20None%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E5%BD%93%E5%89%8D%E8%8A%82%E7%82%B9%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E9%80%92%E5%BD%92%E6%9E%84%E5%BB%BA%E5%B7%A6%E5%8F%B3%E5%AD%90%E6%A0%91%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20*%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20*%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E5%B0%86%E5%88%97%E8%A1%A8%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%BA%E4%BA%8C%E5%8F%89%E6%A0%91%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E5%89%8D%E5%BA%8F%E9%81%8D%E5%8E%86%EF%BC%9A%E4%BE%8B%E9%A2%98%E4%BA%8C%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E5%B0%9D%E8%AF%95%0A%20%20%20%20path.append%28root%29%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%E8%A7%A3%0A%20%20%20%20%20%20%20%20res.append%28list%28path%29%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%20%20%20%20%23%20%E5%9B%9E%E9%80%80%0A%20%20%20%20path.pop%28%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1,%207,%203,%204,%205,%206,%207%5D%29%0A%0A%20%20%20%20%23%20%E5%89%8D%E5%BA%8F%E9%81%8D%E5%8E%86%0A%20%20%20%20path%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20res%20%3D%20list%5Blist%5BTreeNode%5D%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E8%BE%93%E5%87%BA%E6%89%80%E6%9C%89%E6%A0%B9%E8%8A%82%E7%82%B9%E5%88%B0%E8%8A%82%E7%82%B9%207%20%E7%9A%84%E8%B7%AF%E5%BE%84%22%29%0A%20%20%20%20for%20path%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=126&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>In each "try", we record the path by adding the current node to <code>path</code>; before "retreating", we need to pop the node from <code>path</code> <strong>to restore the state before this attempt</strong>.</p>
<p>Observe the process shown below, <strong>we can understand trying and retreating as "advancing" and "undoing"</strong>, two operations that are reverse to each other.</p>
<p>Observe the process shown in Figure 13-2, <strong>we can understand trying and retreating as "advancing" and "undoing"</strong>, two operations that are reverse to each other.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="3:11"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><input id="__tabbed_3_3" name="__tabbed_3" type="radio" /><input id="__tabbed_3_4" name="__tabbed_3" type="radio" /><input id="__tabbed_3_5" name="__tabbed_3" type="radio" /><input id="__tabbed_3_6" name="__tabbed_3" type="radio" /><input id="__tabbed_3_7" name="__tabbed_3" type="radio" /><input id="__tabbed_3_8" name="__tabbed_3" type="radio" /><input id="__tabbed_3_9" name="__tabbed_3" type="radio" /><input id="__tabbed_3_10" name="__tabbed_3" type="radio" /><input id="__tabbed_3_11" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">&lt;1&gt;</label><label for="__tabbed_3_2">&lt;2&gt;</label><label for="__tabbed_3_3">&lt;3&gt;</label><label for="__tabbed_3_4">&lt;4&gt;</label><label for="__tabbed_3_5">&lt;5&gt;</label><label for="__tabbed_3_6">&lt;6&gt;</label><label for="__tabbed_3_7">&lt;7&gt;</label><label for="__tabbed_3_8">&lt;8&gt;</label><label for="__tabbed_3_9">&lt;9&gt;</label><label for="__tabbed_3_10">&lt;10&gt;</label><label for="__tabbed_3_11">&lt;11&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -5406,7 +5406,7 @@
<p>Compared to the implementation based on preorder traversal, the code implementation based on the backtracking algorithm framework seems verbose, but it has better universality. In fact, <strong>many backtracking problems can be solved within this framework</strong>. We just need to define <code>state</code> and <code>choices</code> according to the specific problem and implement the methods in the framework.</p>
<h2 id="1314-common-terminology">13.1.4 &nbsp; Common terminology<a class="headerlink" href="#1314-common-terminology" title="Permanent link">&para;</a></h2>
<p>To analyze algorithmic problems more clearly, we summarize the meanings of commonly used terminology in backtracking algorithms and provide corresponding examples from Example Three as shown in the Table 13-1 .</p>
<p>To analyze algorithmic problems more clearly, we summarize the meanings of commonly used terminology in backtracking algorithms and provide corresponding examples from Example Three as shown in Table 13-1.</p>
<p align="center"> Table 13-1 &nbsp; Common backtracking algorithm terminology </p>
<div class="center-table">

View File

@ -3613,18 +3613,18 @@
<p class="admonition-title">Question</p>
<p>According to the rules of chess, a queen can attack pieces in the same row, column, or on a diagonal line. Given <span class="arithmatex">\(n\)</span> queens and an <span class="arithmatex">\(n \times n\)</span> chessboard, find arrangements where no two queens can attack each other.</p>
</div>
<p>As shown in the Figure 13-15 , when <span class="arithmatex">\(n = 4\)</span>, there are two solutions. From the perspective of the backtracking algorithm, an <span class="arithmatex">\(n \times n\)</span> chessboard has <span class="arithmatex">\(n^2\)</span> squares, presenting all possible choices <code>choices</code>. The state of the chessboard <code>state</code> changes continuously as each queen is placed.</p>
<p>As shown in Figure 13-15, when <span class="arithmatex">\(n = 4\)</span>, there are two solutions. From the perspective of the backtracking algorithm, an <span class="arithmatex">\(n \times n\)</span> chessboard has <span class="arithmatex">\(n^2\)</span> squares, presenting all possible choices <code>choices</code>. The state of the chessboard <code>state</code> changes continuously as each queen is placed.</p>
<p><a class="glightbox" href="../n_queens_problem.assets/solution_4_queens.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Solution to the 4 queens problem" class="animation-figure" src="../n_queens_problem.assets/solution_4_queens.png" /></a></p>
<p align="center"> Figure 13-15 &nbsp; Solution to the 4 queens problem </p>
<p>The following image shows the three constraints of this problem: <strong>multiple queens cannot be on the same row, column, or diagonal</strong>. It is important to note that diagonals are divided into the main diagonal <code>\</code> and the secondary diagonal <code>/</code>.</p>
<p>Figure 13-16 shows the three constraints of this problem: <strong>multiple queens cannot be on the same row, column, or diagonal</strong>. It is important to note that diagonals are divided into the main diagonal <code>\</code> and the secondary diagonal <code>/</code>.</p>
<p><a class="glightbox" href="../n_queens_problem.assets/n_queens_constraints.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Constraints of the n queens problem" class="animation-figure" src="../n_queens_problem.assets/n_queens_constraints.png" /></a></p>
<p align="center"> Figure 13-16 &nbsp; Constraints of the n queens problem </p>
<h3 id="1-row-by-row-placing-strategy">1. &nbsp; Row-by-row placing strategy<a class="headerlink" href="#1-row-by-row-placing-strategy" title="Permanent link">&para;</a></h3>
<p>As the number of queens equals the number of rows on the chessboard, both being <span class="arithmatex">\(n\)</span>, it is easy to conclude: <strong>each row on the chessboard allows and only allows one queen to be placed</strong>.</p>
<p>This means that we can adopt a row-by-row placing strategy: starting from the first row, place one queen per row until the last row is reached.</p>
<p>The image below shows the row-by-row placing process for the 4 queens problem. Due to space limitations, the image only expands one search branch of the first row, and prunes any placements that do not meet the column and diagonal constraints.</p>
<p>Figure 13-17 shows the row-by-row placing process for the 4 queens problem. Due to space limitations, the figure only expands one search branch of the first row, and prunes any placements that do not meet the column and diagonal constraints.</p>
<p><a class="glightbox" href="../n_queens_problem.assets/n_queens_placing.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Row-by-row placing strategy" class="animation-figure" src="../n_queens_problem.assets/n_queens_placing.png" /></a></p>
<p align="center"> Figure 13-17 &nbsp; Row-by-row placing strategy </p>
@ -3632,7 +3632,7 @@
<h3 id="2-column-and-diagonal-pruning">2. &nbsp; Column and diagonal pruning<a class="headerlink" href="#2-column-and-diagonal-pruning" title="Permanent link">&para;</a></h3>
<p>To satisfy column constraints, we can use a boolean array <code>cols</code> of length <span class="arithmatex">\(n\)</span> to track whether a queen occupies each column. Before each placement decision, <code>cols</code> is used to prune the columns that already have queens, and it is dynamically updated during backtracking.</p>
<p>How about the diagonal constraints? Let the row and column indices of a cell on the chessboard be <span class="arithmatex">\((row, col)\)</span>. By selecting a specific main diagonal, we notice that the difference <span class="arithmatex">\(row - col\)</span> is the same for all cells on that diagonal, <strong>meaning that <span class="arithmatex">\(row - col\)</span> is a constant value on that diagonal</strong>.</p>
<p>Thus, if two cells satisfy <span class="arithmatex">\(row_1 - col_1 = row_2 - col_2\)</span>, they are definitely on the same main diagonal. Using this pattern, we can utilize the array <code>diags1</code> shown below to track whether a queen is on any main diagonal.</p>
<p>Thus, if two cells satisfy <span class="arithmatex">\(row_1 - col_1 = row_2 - col_2\)</span>, they are definitely on the same main diagonal. Using this pattern, we can utilize the array <code>diags1</code> shown in Figure 13-18 to track whether a queen is on any main diagonal.</p>
<p>Similarly, <strong>the sum <span class="arithmatex">\(row + col\)</span> is a constant value for all cells on a secondary diagonal</strong>. We can also use the array <code>diags2</code> to handle secondary diagonal constraints.</p>
<p><a class="glightbox" href="../n_queens_problem.assets/n_queens_cols_diagonals.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Handling column and diagonal constraints" class="animation-figure" src="../n_queens_problem.assets/n_queens_cols_diagonals.png" /></a></p>
<p align="center"> Figure 13-18 &nbsp; Handling column and diagonal constraints </p>

View File

@ -3706,7 +3706,7 @@
<!-- Page content -->
<h1 id="132-permutation-problem">13.2 &nbsp; Permutation problem<a class="headerlink" href="#132-permutation-problem" title="Permanent link">&para;</a></h1>
<p>The permutation problem is a typical application of the backtracking algorithm. It is defined as finding all possible arrangements of elements from a given set (such as an array or string).</p>
<p>The Table 13-2 lists several example data, including the input arrays and their corresponding permutations.</p>
<p>Table 13-2 lists several example data, including the input arrays and their corresponding permutations.</p>
<p align="center"> Table 13-2 &nbsp; Permutation examples </p>
<div class="center-table">
@ -3740,7 +3740,7 @@
</div>
<p>From the perspective of the backtracking algorithm, <strong>we can imagine the process of generating permutations as a series of choices</strong>. Suppose the input array is <span class="arithmatex">\([1, 2, 3]\)</span>, if we first choose <span class="arithmatex">\(1\)</span>, then <span class="arithmatex">\(3\)</span>, and finally <span class="arithmatex">\(2\)</span>, we obtain the permutation <span class="arithmatex">\([1, 3, 2]\)</span>. Backtracking means undoing a choice and then continuing to try other choices.</p>
<p>From the code perspective, the candidate set <code>choices</code> contains all elements of the input array, and the state <code>state</code> contains elements that have been selected so far. Please note that each element can only be chosen once, <strong>thus all elements in <code>state</code> must be unique</strong>.</p>
<p>As shown in the following figure, we can unfold the search process into a recursive tree, where each node represents the current state <code>state</code>. Starting from the root node, after three rounds of choices, we reach the leaf nodes, each corresponding to a permutation.</p>
<p>As shown in Figure 13-5, we can unfold the search process into a recursive tree, where each node represents the current state <code>state</code>. Starting from the root node, after three rounds of choices, we reach the leaf nodes, each corresponding to a permutation.</p>
<p><a class="glightbox" href="../permutations_problem.assets/permutations_i.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Permutation recursive tree" class="animation-figure" src="../permutations_problem.assets/permutations_i.png" /></a></p>
<p align="center"> Figure 13-5 &nbsp; Permutation recursive tree </p>
@ -3750,11 +3750,11 @@
<li>After making the choice <code>choice[i]</code>, we set <code>selected[i]</code> to <span class="arithmatex">\(\text{True}\)</span>, indicating it has been chosen.</li>
<li>When iterating through the choice list <code>choices</code>, skip all nodes that have already been selected, i.e., prune.</li>
</ul>
<p>As shown in the following figure, suppose we choose 1 in the first round, 3 in the second round, and 2 in the third round, we need to prune the branch of element 1 in the second round and elements 1 and 3 in the third round.</p>
<p>As shown in Figure 13-6, suppose we choose 1 in the first round, 3 in the second round, and 2 in the third round, we need to prune the branch of element 1 in the second round and elements 1 and 3 in the third round.</p>
<p><a class="glightbox" href="../permutations_problem.assets/permutations_i_pruning.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Permutation pruning example" class="animation-figure" src="../permutations_problem.assets/permutations_i_pruning.png" /></a></p>
<p align="center"> Figure 13-6 &nbsp; Permutation pruning example </p>
<p>Observing the above figure, this pruning operation reduces the search space size from <span class="arithmatex">\(O(n^n)\)</span> to <span class="arithmatex">\(O(n!)\)</span>.</p>
<p>Observing Figure 13-6, this pruning operation reduces the search space size from <span class="arithmatex">\(O(n^n)\)</span> to <span class="arithmatex">\(O(n!)\)</span>.</p>
<h3 id="2-code-implementation">2. &nbsp; Code implementation<a class="headerlink" href="#2-code-implementation" title="Permanent link">&para;</a></h3>
<p>After understanding the above information, we can "fill in the blanks" in the framework code. To shorten the overall code, we do not implement individual functions within the framework code separately, but expand them in the <code>backtrack()</code> function:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:14"><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" /><input id="__tabbed_1_13" name="__tabbed_1" type="radio" /><input id="__tabbed_1_14" 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">Kotlin</label><label for="__tabbed_1_13">Ruby</label><label for="__tabbed_1_14">Zig</label></div>
@ -4208,13 +4208,13 @@
<p>Enter an integer array, <strong>which may contain duplicate elements</strong>, and return all unique permutations.</p>
</div>
<p>Suppose the input array is <span class="arithmatex">\([1, 1, 2]\)</span>. To differentiate the two duplicate elements <span class="arithmatex">\(1\)</span>, we mark the second <span class="arithmatex">\(1\)</span> as <span class="arithmatex">\(\hat{1}\)</span>.</p>
<p>As shown in the following figure, half of the permutations generated by the above method are duplicates.</p>
<p>As shown in Figure 13-7, half of the permutations generated by the above method are duplicates.</p>
<p><a class="glightbox" href="../permutations_problem.assets/permutations_ii.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Duplicate permutations" class="animation-figure" src="../permutations_problem.assets/permutations_ii.png" /></a></p>
<p align="center"> Figure 13-7 &nbsp; Duplicate permutations </p>
<p>So, how do we eliminate duplicate permutations? Most directly, consider using a hash set to deduplicate permutation results. However, this is not elegant, <strong>as branches generating duplicate permutations are unnecessary and should be identified and pruned in advance</strong>, which can further improve algorithm efficiency.</p>
<h3 id="1-pruning-of-equal-elements">1. &nbsp; Pruning of equal elements<a class="headerlink" href="#1-pruning-of-equal-elements" title="Permanent link">&para;</a></h3>
<p>Observing the following figure, in the first round, choosing <span class="arithmatex">\(1\)</span> or <span class="arithmatex">\(\hat{1}\)</span> results in identical permutations under both choices, thus we should prune <span class="arithmatex">\(\hat{1}\)</span>.</p>
<p>Observing Figure 13-8, in the first round, choosing <span class="arithmatex">\(1\)</span> or <span class="arithmatex">\(\hat{1}\)</span> results in identical permutations under both choices, thus we should prune <span class="arithmatex">\(\hat{1}\)</span>.</p>
<p>Similarly, after choosing <span class="arithmatex">\(2\)</span> in the first round, choosing <span class="arithmatex">\(1\)</span> and <span class="arithmatex">\(\hat{1}\)</span> in the second round also produces duplicate branches, so we should also prune <span class="arithmatex">\(\hat{1}\)</span> in the second round.</p>
<p>Essentially, <strong>our goal is to ensure that multiple equal elements are only selected once in each round of choices</strong>.</p>
<p><a class="glightbox" href="../permutations_problem.assets/permutations_ii_pruning.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Duplicate permutations pruning" class="animation-figure" src="../permutations_problem.assets/permutations_ii_pruning.png" /></a></p>
@ -4700,7 +4700,7 @@
<li><strong>Repeated choice pruning</strong>: There is only one <code>selected</code> throughout the search process. It records which elements are currently in the state, aiming to prevent an element from appearing repeatedly in <code>state</code>.</li>
<li><strong>Equal element pruning</strong>: Each round of choices (each call to the <code>backtrack</code> function) contains a <code>duplicated</code>. It records which elements have been chosen in the current traversal (<code>for</code> loop), aiming to ensure equal elements are selected only once.</li>
</ul>
<p>The following figure shows the scope of the two pruning conditions. Note, each node in the tree represents a choice, and the nodes from the root to the leaf form a permutation.</p>
<p>Figure 13-9 shows the scope of the two pruning conditions. Note, each node in the tree represents a choice, and the nodes from the root to the leaf form a permutation.</p>
<p><a class="glightbox" href="../permutations_problem.assets/permutations_ii_pruning_summary.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Scope of the two pruning conditions" class="animation-figure" src="../permutations_problem.assets/permutations_ii_pruning_summary.png" /></a></p>
<p align="center"> Figure 13-9 &nbsp; Scope of the two pruning conditions </p>

View File

@ -4162,7 +4162,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%0A%20%20%20%20target%3A%20int,%0A%20%20%20%20total%3A%20int,%0A%20%20%20%20choices%3A%20list%5Bint%5D,%0A%20%20%20%20res%3A%20list%5Blist%5Bint%5D%5D,%0A%29%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%EF%BC%9A%E5%AD%90%E9%9B%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E5%AD%90%E9%9B%86%E5%92%8C%E7%AD%89%E4%BA%8E%20target%20%E6%97%B6%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%A7%A3%0A%20%20%20%20if%20total%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E6%89%80%E6%9C%89%E9%80%89%E6%8B%A9%0A%20%20%20%20for%20i%20in%20range%28len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%EF%BC%9A%E8%8B%A5%E5%AD%90%E9%9B%86%E5%92%8C%E8%B6%85%E8%BF%87%20target%20%EF%BC%8C%E5%88%99%E8%B7%B3%E8%BF%87%E8%AF%A5%E9%80%89%E6%8B%A9%0A%20%20%20%20%20%20%20%20if%20total%20%2B%20choices%5Bi%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E5%B0%9D%E8%AF%95%EF%BC%9A%E5%81%9A%E5%87%BA%E9%80%89%E6%8B%A9%EF%BC%8C%E6%9B%B4%E6%96%B0%E5%85%83%E7%B4%A0%E5%92%8C%20total%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E8%BD%AE%E9%80%89%E6%8B%A9%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target,%20total%20%2B%20choices%5Bi%5D,%20choices,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%9B%9E%E9%80%80%EF%BC%9A%E6%92%A4%E9%94%80%E9%80%89%E6%8B%A9%EF%BC%8C%E6%81%A2%E5%A4%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E7%9A%84%E7%8A%B6%E6%80%81%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i_naive%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E5%AD%90%E9%9B%86%E5%92%8C%20I%EF%BC%88%E5%8C%85%E5%90%AB%E9%87%8D%E5%A4%8D%E5%AD%90%E9%9B%86%EF%BC%89%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%80%81%EF%BC%88%E5%AD%90%E9%9B%86%EF%BC%89%0A%20%20%20%20total%20%3D%200%20%20%23%20%E5%AD%90%E9%9B%86%E5%92%8C%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%BB%93%E6%9E%9C%E5%88%97%E8%A1%A8%EF%BC%88%E5%AD%90%E9%9B%86%E5%88%97%E8%A1%A8%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20total,%20nums,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i_naive%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%95%B0%E7%BB%84%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E6%89%80%E6%9C%89%E5%92%8C%E7%AD%89%E4%BA%8E%20%7Btarget%7D%20%E7%9A%84%E5%AD%90%E9%9B%86%20res%20%3D%20%7Bres%7D%22%29%0A%20%20%20%20print%28f%22%E8%AF%B7%E6%B3%A8%E6%84%8F%EF%BC%8C%E8%AF%A5%E6%96%B9%E6%B3%95%E8%BE%93%E5%87%BA%E7%9A%84%E7%BB%93%E6%9E%9C%E5%8C%85%E5%90%AB%E9%87%8D%E5%A4%8D%E9%9B%86%E5%90%88%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>Inputting the array <span class="arithmatex">\([3, 4, 5]\)</span> and target element <span class="arithmatex">\(9\)</span> into the above code yields the results <span class="arithmatex">\([3, 3, 3], [4, 5], [5, 4]\)</span>. <strong>Although it successfully finds all subsets with a sum of <span class="arithmatex">\(9\)</span>, it includes the duplicate subset <span class="arithmatex">\([4, 5]\)</span> and <span class="arithmatex">\([5, 4]\)</span></strong>.</p>
<p>This is because the search process distinguishes the order of choices, however, subsets do not distinguish the choice order. As shown in the following figure, choosing <span class="arithmatex">\(4\)</span> before <span class="arithmatex">\(5\)</span> and choosing <span class="arithmatex">\(5\)</span> before <span class="arithmatex">\(4\)</span> are different branches, but correspond to the same subset.</p>
<p>This is because the search process distinguishes the order of choices, however, subsets do not distinguish the choice order. As shown in Figure 13-10, choosing <span class="arithmatex">\(4\)</span> before <span class="arithmatex">\(5\)</span> and choosing <span class="arithmatex">\(5\)</span> before <span class="arithmatex">\(4\)</span> are different branches, but correspond to the same subset.</p>
<p><a class="glightbox" href="../subset_sum_problem.assets/subset_sum_i_naive.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Subset search and pruning out of bounds" class="animation-figure" src="../subset_sum_problem.assets/subset_sum_i_naive.png" /></a></p>
<p align="center"> Figure 13-10 &nbsp; Subset search and pruning out of bounds </p>
@ -4172,7 +4172,7 @@
<li>Comparing subsets (arrays) for differences is very time-consuming, requiring arrays to be sorted first, then comparing the differences of each element in the arrays.</li>
</ul>
<h3 id="2-duplicate-subset-pruning">2. &nbsp; Duplicate subset pruning<a class="headerlink" href="#2-duplicate-subset-pruning" title="Permanent link">&para;</a></h3>
<p><strong>We consider deduplication during the search process through pruning</strong>. Observing the following figure, duplicate subsets are generated when choosing array elements in different orders, for example in the following situations.</p>
<p><strong>We consider deduplication during the search process through pruning</strong>. Observing Figure 13-11, duplicate subsets are generated when choosing array elements in different orders, for example in the following situations.</p>
<ol>
<li>When choosing <span class="arithmatex">\(3\)</span> in the first round and <span class="arithmatex">\(4\)</span> in the second round, all subsets containing these two elements are generated, denoted as <span class="arithmatex">\([3, 4, \dots]\)</span>.</li>
<li>Later, when <span class="arithmatex">\(4\)</span> is chosen in the first round, <strong>the second round should skip <span class="arithmatex">\(3\)</span></strong> because the subset <span class="arithmatex">\([4, 3, \dots]\)</span> generated by this choice completely duplicates the subset from step <code>1.</code>.</li>
@ -4670,7 +4670,7 @@
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20target%3A%20int,%20choices%3A%20list%5Bint%5D,%20start%3A%20int,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%EF%BC%9A%E5%AD%90%E9%9B%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E5%AD%90%E9%9B%86%E5%92%8C%E7%AD%89%E4%BA%8E%20target%20%E6%97%B6%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%A7%A3%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E6%89%80%E6%9C%89%E9%80%89%E6%8B%A9%0A%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%BA%8C%EF%BC%9A%E4%BB%8E%20start%20%E5%BC%80%E5%A7%8B%E9%81%8D%E5%8E%86%EF%BC%8C%E9%81%BF%E5%85%8D%E7%94%9F%E6%88%90%E9%87%8D%E5%A4%8D%E5%AD%90%E9%9B%86%0A%20%20%20%20for%20i%20in%20range%28start,%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%B8%80%EF%BC%9A%E8%8B%A5%E5%AD%90%E9%9B%86%E5%92%8C%E8%B6%85%E8%BF%87%20target%20%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E7%BB%93%E6%9D%9F%E5%BE%AA%E7%8E%AF%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%E6%95%B0%E7%BB%84%E5%B7%B2%E6%8E%92%E5%BA%8F%EF%BC%8C%E5%90%8E%E8%BE%B9%E5%85%83%E7%B4%A0%E6%9B%B4%E5%A4%A7%EF%BC%8C%E5%AD%90%E9%9B%86%E5%92%8C%E4%B8%80%E5%AE%9A%E8%B6%85%E8%BF%87%20target%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E5%B0%9D%E8%AF%95%EF%BC%9A%E5%81%9A%E5%87%BA%E9%80%89%E6%8B%A9%EF%BC%8C%E6%9B%B4%E6%96%B0%20target,%20start%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E8%BD%AE%E9%80%89%E6%8B%A9%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target%20-%20choices%5Bi%5D,%20choices,%20i,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%9B%9E%E9%80%80%EF%BC%9A%E6%92%A4%E9%94%80%E9%80%89%E6%8B%A9%EF%BC%8C%E6%81%A2%E5%A4%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E7%9A%84%E7%8A%B6%E6%80%81%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E5%AD%90%E9%9B%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%80%81%EF%BC%88%E5%AD%90%E9%9B%86%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20%E5%AF%B9%20nums%20%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%0A%20%20%20%20start%20%3D%200%20%20%23%20%E9%81%8D%E5%8E%86%E8%B5%B7%E5%A7%8B%E7%82%B9%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%BB%93%E6%9E%9C%E5%88%97%E8%A1%A8%EF%BC%88%E5%AD%90%E9%9B%86%E5%88%97%E8%A1%A8%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20nums,%20start,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%95%B0%E7%BB%84%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E6%89%80%E6%9C%89%E5%92%8C%E7%AD%89%E4%BA%8E%20%7Btarget%7D%20%E7%9A%84%E5%AD%90%E9%9B%86%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20target%3A%20int,%20choices%3A%20list%5Bint%5D,%20start%3A%20int,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%EF%BC%9A%E5%AD%90%E9%9B%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E5%AD%90%E9%9B%86%E5%92%8C%E7%AD%89%E4%BA%8E%20target%20%E6%97%B6%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%A7%A3%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E6%89%80%E6%9C%89%E9%80%89%E6%8B%A9%0A%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%BA%8C%EF%BC%9A%E4%BB%8E%20start%20%E5%BC%80%E5%A7%8B%E9%81%8D%E5%8E%86%EF%BC%8C%E9%81%BF%E5%85%8D%E7%94%9F%E6%88%90%E9%87%8D%E5%A4%8D%E5%AD%90%E9%9B%86%0A%20%20%20%20for%20i%20in%20range%28start,%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%B8%80%EF%BC%9A%E8%8B%A5%E5%AD%90%E9%9B%86%E5%92%8C%E8%B6%85%E8%BF%87%20target%20%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E7%BB%93%E6%9D%9F%E5%BE%AA%E7%8E%AF%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%E6%95%B0%E7%BB%84%E5%B7%B2%E6%8E%92%E5%BA%8F%EF%BC%8C%E5%90%8E%E8%BE%B9%E5%85%83%E7%B4%A0%E6%9B%B4%E5%A4%A7%EF%BC%8C%E5%AD%90%E9%9B%86%E5%92%8C%E4%B8%80%E5%AE%9A%E8%B6%85%E8%BF%87%20target%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E5%B0%9D%E8%AF%95%EF%BC%9A%E5%81%9A%E5%87%BA%E9%80%89%E6%8B%A9%EF%BC%8C%E6%9B%B4%E6%96%B0%20target,%20start%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E8%BD%AE%E9%80%89%E6%8B%A9%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target%20-%20choices%5Bi%5D,%20choices,%20i,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%9B%9E%E9%80%80%EF%BC%9A%E6%92%A4%E9%94%80%E9%80%89%E6%8B%A9%EF%BC%8C%E6%81%A2%E5%A4%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E7%9A%84%E7%8A%B6%E6%80%81%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E5%AD%90%E9%9B%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%80%81%EF%BC%88%E5%AD%90%E9%9B%86%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20%E5%AF%B9%20nums%20%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%0A%20%20%20%20start%20%3D%200%20%20%23%20%E9%81%8D%E5%8E%86%E8%B5%B7%E5%A7%8B%E7%82%B9%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%BB%93%E6%9E%9C%E5%88%97%E8%A1%A8%EF%BC%88%E5%AD%90%E9%9B%86%E5%88%97%E8%A1%A8%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20nums,%20start,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%95%B0%E7%BB%84%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E6%89%80%E6%9C%89%E5%92%8C%E7%AD%89%E4%BA%8E%20%7Btarget%7D%20%E7%9A%84%E5%AD%90%E9%9B%86%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following figure shows the overall backtracking process after inputting the array <span class="arithmatex">\([3, 4, 5]\)</span> and target element <span class="arithmatex">\(9\)</span> into the above code.</p>
<p>Figure 13-12 shows the overall backtracking process after inputting the array <span class="arithmatex">\([3, 4, 5]\)</span> and target element <span class="arithmatex">\(9\)</span> into the above code.</p>
<p><a class="glightbox" href="../subset_sum_problem.assets/subset_sum_i.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Subset sum I backtracking process" class="animation-figure" src="../subset_sum_problem.assets/subset_sum_i.png" /></a></p>
<p align="center"> Figure 13-12 &nbsp; Subset sum I backtracking process </p>
@ -4680,7 +4680,7 @@
<p>Given an array of positive integers <code>nums</code> and a target positive integer <code>target</code>, find all possible combinations such that the sum of the elements in the combination equals <code>target</code>. <strong>The given array may contain duplicate elements, and each element can only be chosen once</strong>. Please return these combinations as a list, which should not contain duplicate combinations.</p>
</div>
<p>Compared to the previous question, <strong>this question's input array may contain duplicate elements</strong>, introducing new problems. For example, given the array <span class="arithmatex">\([4, \hat{4}, 5]\)</span> and target element <span class="arithmatex">\(9\)</span>, the existing code's output results in <span class="arithmatex">\([4, 5], [\hat{4}, 5]\)</span>, resulting in duplicate subsets.</p>
<p><strong>The reason for this duplication is that equal elements are chosen multiple times in a certain round</strong>. In the following figure, the first round has three choices, two of which are <span class="arithmatex">\(4\)</span>, generating two duplicate search branches, thus outputting duplicate subsets; similarly, the two <span class="arithmatex">\(4\)</span>s in the second round also produce duplicate subsets.</p>
<p><strong>The reason for this duplication is that equal elements are chosen multiple times in a certain round</strong>. In Figure 13-13, the first round has three choices, two of which are <span class="arithmatex">\(4\)</span>, generating two duplicate search branches, thus outputting duplicate subsets; similarly, the two <span class="arithmatex">\(4\)</span>s in the second round also produce duplicate subsets.</p>
<p><a class="glightbox" href="../subset_sum_problem.assets/subset_sum_ii_repeat.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Duplicate subsets caused by equal elements" class="animation-figure" src="../subset_sum_problem.assets/subset_sum_ii_repeat.png" /></a></p>
<p align="center"> Figure 13-13 &nbsp; Duplicate subsets caused by equal elements </p>
@ -5223,7 +5223,7 @@
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20target%3A%20int,%20choices%3A%20list%5Bint%5D,%20start%3A%20int,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%EF%BC%9A%E5%AD%90%E9%9B%86%E5%92%8C%20II%22%22%22%0A%20%20%20%20%23%20%E5%AD%90%E9%9B%86%E5%92%8C%E7%AD%89%E4%BA%8E%20target%20%E6%97%B6%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%A7%A3%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E6%89%80%E6%9C%89%E9%80%89%E6%8B%A9%0A%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%BA%8C%EF%BC%9A%E4%BB%8E%20start%20%E5%BC%80%E5%A7%8B%E9%81%8D%E5%8E%86%EF%BC%8C%E9%81%BF%E5%85%8D%E7%94%9F%E6%88%90%E9%87%8D%E5%A4%8D%E5%AD%90%E9%9B%86%0A%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%B8%89%EF%BC%9A%E4%BB%8E%20start%20%E5%BC%80%E5%A7%8B%E9%81%8D%E5%8E%86%EF%BC%8C%E9%81%BF%E5%85%8D%E9%87%8D%E5%A4%8D%E9%80%89%E6%8B%A9%E5%90%8C%E4%B8%80%E5%85%83%E7%B4%A0%0A%20%20%20%20for%20i%20in%20range%28start,%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%B8%80%EF%BC%9A%E8%8B%A5%E5%AD%90%E9%9B%86%E5%92%8C%E8%B6%85%E8%BF%87%20target%20%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E7%BB%93%E6%9D%9F%E5%BE%AA%E7%8E%AF%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%E6%95%B0%E7%BB%84%E5%B7%B2%E6%8E%92%E5%BA%8F%EF%BC%8C%E5%90%8E%E8%BE%B9%E5%85%83%E7%B4%A0%E6%9B%B4%E5%A4%A7%EF%BC%8C%E5%AD%90%E9%9B%86%E5%92%8C%E4%B8%80%E5%AE%9A%E8%B6%85%E8%BF%87%20target%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E5%9B%9B%EF%BC%9A%E5%A6%82%E6%9E%9C%E8%AF%A5%E5%85%83%E7%B4%A0%E4%B8%8E%E5%B7%A6%E8%BE%B9%E5%85%83%E7%B4%A0%E7%9B%B8%E7%AD%89%EF%BC%8C%E8%AF%B4%E6%98%8E%E8%AF%A5%E6%90%9C%E7%B4%A2%E5%88%86%E6%94%AF%E9%87%8D%E5%A4%8D%EF%BC%8C%E7%9B%B4%E6%8E%A5%E8%B7%B3%E8%BF%87%0A%20%20%20%20%20%20%20%20if%20i%20%3E%20start%20and%20choices%5Bi%5D%20%3D%3D%20choices%5Bi%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E5%B0%9D%E8%AF%95%EF%BC%9A%E5%81%9A%E5%87%BA%E9%80%89%E6%8B%A9%EF%BC%8C%E6%9B%B4%E6%96%B0%20target,%20start%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E8%BD%AE%E9%80%89%E6%8B%A9%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target%20-%20choices%5Bi%5D,%20choices,%20i%20%2B%201,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%9B%9E%E9%80%80%EF%BC%9A%E6%92%A4%E9%94%80%E9%80%89%E6%8B%A9%EF%BC%8C%E6%81%A2%E5%A4%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E7%9A%84%E7%8A%B6%E6%80%81%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_ii%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E5%AD%90%E9%9B%86%E5%92%8C%20II%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%80%81%EF%BC%88%E5%AD%90%E9%9B%86%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20%E5%AF%B9%20nums%20%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%0A%20%20%20%20start%20%3D%200%20%20%23%20%E9%81%8D%E5%8E%86%E8%B5%B7%E5%A7%8B%E7%82%B9%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%BB%93%E6%9E%9C%E5%88%97%E8%A1%A8%EF%BC%88%E5%AD%90%E9%9B%86%E5%88%97%E8%A1%A8%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20nums,%20start,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_ii%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%95%B0%E7%BB%84%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E6%89%80%E6%9C%89%E5%92%8C%E7%AD%89%E4%BA%8E%20%7Btarget%7D%20%E7%9A%84%E5%AD%90%E9%9B%86%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20target%3A%20int,%20choices%3A%20list%5Bint%5D,%20start%3A%20int,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%EF%BC%9A%E5%AD%90%E9%9B%86%E5%92%8C%20II%22%22%22%0A%20%20%20%20%23%20%E5%AD%90%E9%9B%86%E5%92%8C%E7%AD%89%E4%BA%8E%20target%20%E6%97%B6%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%A7%A3%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E6%89%80%E6%9C%89%E9%80%89%E6%8B%A9%0A%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%BA%8C%EF%BC%9A%E4%BB%8E%20start%20%E5%BC%80%E5%A7%8B%E9%81%8D%E5%8E%86%EF%BC%8C%E9%81%BF%E5%85%8D%E7%94%9F%E6%88%90%E9%87%8D%E5%A4%8D%E5%AD%90%E9%9B%86%0A%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%B8%89%EF%BC%9A%E4%BB%8E%20start%20%E5%BC%80%E5%A7%8B%E9%81%8D%E5%8E%86%EF%BC%8C%E9%81%BF%E5%85%8D%E9%87%8D%E5%A4%8D%E9%80%89%E6%8B%A9%E5%90%8C%E4%B8%80%E5%85%83%E7%B4%A0%0A%20%20%20%20for%20i%20in%20range%28start,%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E4%B8%80%EF%BC%9A%E8%8B%A5%E5%AD%90%E9%9B%86%E5%92%8C%E8%B6%85%E8%BF%87%20target%20%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E7%BB%93%E6%9D%9F%E5%BE%AA%E7%8E%AF%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%E6%95%B0%E7%BB%84%E5%B7%B2%E6%8E%92%E5%BA%8F%EF%BC%8C%E5%90%8E%E8%BE%B9%E5%85%83%E7%B4%A0%E6%9B%B4%E5%A4%A7%EF%BC%8C%E5%AD%90%E9%9B%86%E5%92%8C%E4%B8%80%E5%AE%9A%E8%B6%85%E8%BF%87%20target%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E5%89%AA%E6%9E%9D%E5%9B%9B%EF%BC%9A%E5%A6%82%E6%9E%9C%E8%AF%A5%E5%85%83%E7%B4%A0%E4%B8%8E%E5%B7%A6%E8%BE%B9%E5%85%83%E7%B4%A0%E7%9B%B8%E7%AD%89%EF%BC%8C%E8%AF%B4%E6%98%8E%E8%AF%A5%E6%90%9C%E7%B4%A2%E5%88%86%E6%94%AF%E9%87%8D%E5%A4%8D%EF%BC%8C%E7%9B%B4%E6%8E%A5%E8%B7%B3%E8%BF%87%0A%20%20%20%20%20%20%20%20if%20i%20%3E%20start%20and%20choices%5Bi%5D%20%3D%3D%20choices%5Bi%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E5%B0%9D%E8%AF%95%EF%BC%9A%E5%81%9A%E5%87%BA%E9%80%89%E6%8B%A9%EF%BC%8C%E6%9B%B4%E6%96%B0%20target,%20start%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E8%BD%AE%E9%80%89%E6%8B%A9%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target%20-%20choices%5Bi%5D,%20choices,%20i%20%2B%201,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%9B%9E%E9%80%80%EF%BC%9A%E6%92%A4%E9%94%80%E9%80%89%E6%8B%A9%EF%BC%8C%E6%81%A2%E5%A4%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E7%9A%84%E7%8A%B6%E6%80%81%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_ii%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E5%AD%90%E9%9B%86%E5%92%8C%20II%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%80%81%EF%BC%88%E5%AD%90%E9%9B%86%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20%E5%AF%B9%20nums%20%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%0A%20%20%20%20start%20%3D%200%20%20%23%20%E9%81%8D%E5%8E%86%E8%B5%B7%E5%A7%8B%E7%82%B9%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%BB%93%E6%9E%9C%E5%88%97%E8%A1%A8%EF%BC%88%E5%AD%90%E9%9B%86%E5%88%97%E8%A1%A8%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20nums,%20start,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_ii%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%95%B0%E7%BB%84%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E6%89%80%E6%9C%89%E5%92%8C%E7%AD%89%E4%BA%8E%20%7Btarget%7D%20%E7%9A%84%E5%AD%90%E9%9B%86%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following figure shows the backtracking process for the array <span class="arithmatex">\([4, 4, 5]\)</span> and target element <span class="arithmatex">\(9\)</span>, including four types of pruning operations. Please combine the illustration with the code comments to understand the entire search process and how each type of pruning operation works.</p>
<p>Figure 13-14 shows the backtracking process for the array <span class="arithmatex">\([4, 4, 5]\)</span> and target element <span class="arithmatex">\(9\)</span>, including four types of pruning operations. Please combine the illustration with the code comments to understand the entire search process and how each type of pruning operation works.</p>
<p><a class="glightbox" href="../subset_sum_problem.assets/subset_sum_ii.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Subset sum II backtracking process" class="animation-figure" src="../subset_sum_problem.assets/subset_sum_ii.png" /></a></p>
<p align="center"> Figure 13-14 &nbsp; Subset sum II backtracking process </p>

View File

@ -4814,7 +4814,7 @@
<p><div style="height: 459px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%80%92%E5%BD%92%22%22%22%0A%20%20%20%20%23%20%E7%BB%88%E6%AD%A2%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E9%80%92%EF%BC%9A%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%0A%20%20%20%20res%20%3D%20recur%28n%20-%201%29%0A%20%20%20%20%23%20%E5%BD%92%EF%BC%9A%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0A%20%20%20%20return%20n%20%2B%20res%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0%E7%9A%84%E6%B1%82%E5%92%8C%E7%BB%93%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=3&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%80%92%E5%BD%92%22%22%22%0A%20%20%20%20%23%20%E7%BB%88%E6%AD%A2%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E9%80%92%EF%BC%9A%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%0A%20%20%20%20res%20%3D%20recur%28n%20-%201%29%0A%20%20%20%20%23%20%E5%BD%92%EF%BC%9A%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0A%20%20%20%20return%20n%20%2B%20res%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0%E7%9A%84%E6%B1%82%E5%92%8C%E7%BB%93%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=3&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The Figure 2-3 shows the recursive process of this function.</p>
<p>Figure 2-3 shows the recursive process of this function.</p>
<p><a class="glightbox" href="../iteration_and_recursion.assets/recursion_sum.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursive process of the sum function" class="animation-figure" src="../iteration_and_recursion.assets/recursion_sum.png" /></a></p>
<p align="center"> Figure 2-3 &nbsp; Recursive process of the sum function </p>
@ -4834,7 +4834,7 @@
<li>The function's context data is stored in a memory area called "stack frame space" and is only released after the function returns. Therefore, <strong>recursion generally consumes more memory space than iteration</strong>.</li>
<li>Recursive calls introduce additional overhead. <strong>Hence, recursion is usually less time-efficient than loops.</strong></li>
</ul>
<p>As shown in the Figure 2-4 , there are <span class="arithmatex">\(n\)</span> unreturned recursive functions before triggering the termination condition, indicating a <strong>recursion depth of <span class="arithmatex">\(n\)</span></strong>.</p>
<p>As shown in Figure 2-4, there are <span class="arithmatex">\(n\)</span> unreturned recursive functions before triggering the termination condition, indicating a <strong>recursion depth of <span class="arithmatex">\(n\)</span></strong>.</p>
<p><a class="glightbox" href="../iteration_and_recursion.assets/recursion_sum_depth.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursion call depth" class="animation-figure" src="../iteration_and_recursion.assets/recursion_sum_depth.png" /></a></p>
<p align="center"> Figure 2-4 &nbsp; Recursion call depth </p>
@ -5009,7 +5009,7 @@
<p><div style="height: 423px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20tail_recur%28n,%20res%29%3A%0A%20%20%20%20%22%22%22%E5%B0%BE%E9%80%92%E5%BD%92%22%22%22%0A%20%20%20%20%23%20%E7%BB%88%E6%AD%A2%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20res%0A%20%20%20%20%23%20%E5%B0%BE%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%0A%20%20%20%20return%20tail_recur%28n%20-%201,%20res%20%2B%20n%29%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20tail_recur%28n,%200%29%0A%20%20%20%20print%28f%22%5Cn%E5%B0%BE%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0%E7%9A%84%E6%B1%82%E5%92%8C%E7%BB%93%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=3&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20tail_recur%28n,%20res%29%3A%0A%20%20%20%20%22%22%22%E5%B0%BE%E9%80%92%E5%BD%92%22%22%22%0A%20%20%20%20%23%20%E7%BB%88%E6%AD%A2%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20res%0A%20%20%20%20%23%20%E5%B0%BE%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%0A%20%20%20%20return%20tail_recur%28n%20-%201,%20res%20%2B%20n%29%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20tail_recur%28n,%200%29%0A%20%20%20%20print%28f%22%5Cn%E5%B0%BE%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0%E7%9A%84%E6%B1%82%E5%92%8C%E7%BB%93%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=3&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The execution process of tail recursion is shown in the following figure. Comparing regular recursion and tail recursion, the point of the summation operation is different.</p>
<p>The execution process of tail recursion is shown in Figure 2-5. Comparing regular recursion and tail recursion, the point of the summation operation is different.</p>
<ul>
<li><strong>Regular recursion</strong>: The summation operation occurs during the "returning" phase, requiring another summation after each layer returns.</li>
<li><strong>Tail recursion</strong>: The summation operation occurs during the "calling" phase, and the "returning" phase only involves returning through each layer.</li>

View File

@ -3744,7 +3744,7 @@
<li><strong>Stack frame space</strong>: Used to save the context data of the called function. The system creates a stack frame at the top of the stack each time a function is called, and the stack frame space is released after the function returns.</li>
<li><strong>Instruction space</strong>: Used to store compiled program instructions, which are usually negligible in actual statistics.</li>
</ul>
<p>When analyzing the space complexity of a program, <strong>we typically count the Temporary Data, Stack Frame Space, and Output Data</strong>, as shown in the Figure 2-15 .</p>
<p>When analyzing the space complexity of a program, <strong>we typically count the Temporary Data, Stack Frame Space, and Output Data</strong>, as shown in Figure 2-15.</p>
<p><a class="glightbox" href="../space_complexity.assets/space_types.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Space types used in algorithms" class="animation-figure" src="../space_complexity.assets/space_types.png" /></a></p>
<p align="center"> Figure 2-15 &nbsp; Space types used in algorithms </p>
@ -5036,7 +5036,7 @@ O(1) &lt; O(\log n) &lt; O(n) &lt; O(n^2) &lt; O(2^n) \newline
<p><div style="height: 477px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20linear%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E7%BA%BF%E6%80%A7%E9%98%B6%22%22%22%0A%20%20%20%20%23%20%E9%95%BF%E5%BA%A6%E4%B8%BA%20n%20%E7%9A%84%E5%88%97%E8%A1%A8%E5%8D%A0%E7%94%A8%20O%28n%29%20%E7%A9%BA%E9%97%B4%0A%20%20%20%20nums%20%3D%20%5B0%5D%20*%20n%0A%20%20%20%20%23%20%E9%95%BF%E5%BA%A6%E4%B8%BA%20n%20%E7%9A%84%E5%93%88%E5%B8%8C%E8%A1%A8%E5%8D%A0%E7%94%A8%20O%28n%29%20%E7%A9%BA%E9%97%B4%0A%20%20%20%20hmap%20%3D%20dict%5Bint,%20str%5D%28%29%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20hmap%5Bi%5D%20%3D%20str%28i%29%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E7%BA%BF%E6%80%A7%E9%98%B6%0A%20%20%20%20linear%28n%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=20&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20linear%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E7%BA%BF%E6%80%A7%E9%98%B6%22%22%22%0A%20%20%20%20%23%20%E9%95%BF%E5%BA%A6%E4%B8%BA%20n%20%E7%9A%84%E5%88%97%E8%A1%A8%E5%8D%A0%E7%94%A8%20O%28n%29%20%E7%A9%BA%E9%97%B4%0A%20%20%20%20nums%20%3D%20%5B0%5D%20*%20n%0A%20%20%20%20%23%20%E9%95%BF%E5%BA%A6%E4%B8%BA%20n%20%E7%9A%84%E5%93%88%E5%B8%8C%E8%A1%A8%E5%8D%A0%E7%94%A8%20O%28n%29%20%E7%A9%BA%E9%97%B4%0A%20%20%20%20hmap%20%3D%20dict%5Bint,%20str%5D%28%29%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20hmap%5Bi%5D%20%3D%20str%28i%29%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E7%BA%BF%E6%80%A7%E9%98%B6%0A%20%20%20%20linear%28n%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=20&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown below, this function's recursive depth is <span class="arithmatex">\(n\)</span>, meaning there are <span class="arithmatex">\(n\)</span> instances of unreturned <code>linear_recur()</code> function, using <span class="arithmatex">\(O(n)\)</span> size of stack frame space:</p>
<p>As shown in Figure 2-17, this function's recursive depth is <span class="arithmatex">\(n\)</span>, meaning there are <span class="arithmatex">\(n\)</span> instances of unreturned <code>linear_recur()</code> function, using <span class="arithmatex">\(O(n)\)</span> size of stack frame space:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="6:14"><input checked="checked" id="__tabbed_6_1" name="__tabbed_6" type="radio" /><input id="__tabbed_6_2" name="__tabbed_6" type="radio" /><input id="__tabbed_6_3" name="__tabbed_6" type="radio" /><input id="__tabbed_6_4" name="__tabbed_6" type="radio" /><input id="__tabbed_6_5" name="__tabbed_6" type="radio" /><input id="__tabbed_6_6" name="__tabbed_6" type="radio" /><input id="__tabbed_6_7" name="__tabbed_6" type="radio" /><input id="__tabbed_6_8" name="__tabbed_6" type="radio" /><input id="__tabbed_6_9" name="__tabbed_6" type="radio" /><input id="__tabbed_6_10" name="__tabbed_6" type="radio" /><input id="__tabbed_6_11" name="__tabbed_6" type="radio" /><input id="__tabbed_6_12" name="__tabbed_6" type="radio" /><input id="__tabbed_6_13" name="__tabbed_6" type="radio" /><input id="__tabbed_6_14" name="__tabbed_6" type="radio" /><div class="tabbed-labels"><label for="__tabbed_6_1">Python</label><label for="__tabbed_6_2">C++</label><label for="__tabbed_6_3">Java</label><label for="__tabbed_6_4">C#</label><label for="__tabbed_6_5">Go</label><label for="__tabbed_6_6">Swift</label><label for="__tabbed_6_7">JS</label><label for="__tabbed_6_8">TS</label><label for="__tabbed_6_9">Dart</label><label for="__tabbed_6_10">Rust</label><label for="__tabbed_6_11">C</label><label for="__tabbed_6_12">Kotlin</label><label for="__tabbed_6_13">Ruby</label><label for="__tabbed_6_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -5409,7 +5409,7 @@ O(1) &lt; O(\log n) &lt; O(n) &lt; O(n^2) &lt; O(2^n) \newline
<p><div style="height: 405px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20quadratic%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%B9%B3%E6%96%B9%E9%98%B6%22%22%22%0A%20%20%20%20%23%20%E4%BA%8C%E7%BB%B4%E5%88%97%E8%A1%A8%E5%8D%A0%E7%94%A8%20O%28n%5E2%29%20%E7%A9%BA%E9%97%B4%0A%20%20%20%20num_matrix%20%3D%20%5B%5B0%5D%20*%20n%20for%20_%20in%20range%28n%29%5D%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E5%B9%B3%E6%96%B9%E9%98%B6%0A%20%20%20%20quadratic%28n%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20quadratic%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%B9%B3%E6%96%B9%E9%98%B6%22%22%22%0A%20%20%20%20%23%20%E4%BA%8C%E7%BB%B4%E5%88%97%E8%A1%A8%E5%8D%A0%E7%94%A8%20O%28n%5E2%29%20%E7%A9%BA%E9%97%B4%0A%20%20%20%20num_matrix%20%3D%20%5B%5B0%5D%20*%20n%20for%20_%20in%20range%28n%29%5D%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E5%B9%B3%E6%96%B9%E9%98%B6%0A%20%20%20%20quadratic%28n%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown below, the recursive depth of this function is <span class="arithmatex">\(n\)</span>, and in each recursive call, an array is initialized with lengths <span class="arithmatex">\(n\)</span>, <span class="arithmatex">\(n-1\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(2\)</span>, <span class="arithmatex">\(1\)</span>, averaging <span class="arithmatex">\(n/2\)</span>, thus overall occupying <span class="arithmatex">\(O(n^2)\)</span> space:</p>
<p>As shown in Figure 2-18, the recursive depth of this function is <span class="arithmatex">\(n\)</span>, and in each recursive call, an array is initialized with lengths <span class="arithmatex">\(n\)</span>, <span class="arithmatex">\(n-1\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(2\)</span>, <span class="arithmatex">\(1\)</span>, averaging <span class="arithmatex">\(n/2\)</span>, thus overall occupying <span class="arithmatex">\(O(n^2)\)</span> space:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="8:14"><input checked="checked" id="__tabbed_8_1" name="__tabbed_8" type="radio" /><input id="__tabbed_8_2" name="__tabbed_8" type="radio" /><input id="__tabbed_8_3" name="__tabbed_8" type="radio" /><input id="__tabbed_8_4" name="__tabbed_8" type="radio" /><input id="__tabbed_8_5" name="__tabbed_8" type="radio" /><input id="__tabbed_8_6" name="__tabbed_8" type="radio" /><input id="__tabbed_8_7" name="__tabbed_8" type="radio" /><input id="__tabbed_8_8" name="__tabbed_8" type="radio" /><input id="__tabbed_8_9" name="__tabbed_8" type="radio" /><input id="__tabbed_8_10" name="__tabbed_8" type="radio" /><input id="__tabbed_8_11" name="__tabbed_8" type="radio" /><input id="__tabbed_8_12" name="__tabbed_8" type="radio" /><input id="__tabbed_8_13" name="__tabbed_8" type="radio" /><input id="__tabbed_8_14" name="__tabbed_8" type="radio" /><div class="tabbed-labels"><label for="__tabbed_8_1">Python</label><label for="__tabbed_8_2">C++</label><label for="__tabbed_8_3">Java</label><label for="__tabbed_8_4">C#</label><label for="__tabbed_8_5">Go</label><label for="__tabbed_8_6">Swift</label><label for="__tabbed_8_7">JS</label><label for="__tabbed_8_8">TS</label><label for="__tabbed_8_9">Dart</label><label for="__tabbed_8_10">Rust</label><label for="__tabbed_8_11">C</label><label for="__tabbed_8_12">Kotlin</label><label for="__tabbed_8_13">Ruby</label><label for="__tabbed_8_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -5581,7 +5581,7 @@ O(1) &lt; O(\log n) &lt; O(n) &lt; O(n^2) &lt; O(2^n) \newline
<p align="center"> Figure 2-18 &nbsp; Recursive function generating quadratic order space complexity </p>
<h3 id="4-exponential-order-o2n">4. &nbsp; Exponential order <span class="arithmatex">\(O(2^n)\)</span><a class="headerlink" href="#4-exponential-order-o2n" title="Permanent link">&para;</a></h3>
<p>Exponential order is common in binary trees. Observe the below image, a "full binary tree" with <span class="arithmatex">\(n\)</span> levels has <span class="arithmatex">\(2^n - 1\)</span> nodes, occupying <span class="arithmatex">\(O(2^n)\)</span> space:</p>
<p>Exponential order is common in binary trees. Observe Figure 2-19, a "full binary tree" with <span class="arithmatex">\(n\)</span> levels has <span class="arithmatex">\(2^n - 1\)</span> nodes, occupying <span class="arithmatex">\(O(2^n)\)</span> space:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="9:14"><input checked="checked" id="__tabbed_9_1" name="__tabbed_9" type="radio" /><input id="__tabbed_9_2" name="__tabbed_9" type="radio" /><input id="__tabbed_9_3" name="__tabbed_9" type="radio" /><input id="__tabbed_9_4" name="__tabbed_9" type="radio" /><input id="__tabbed_9_5" name="__tabbed_9" type="radio" /><input id="__tabbed_9_6" name="__tabbed_9" type="radio" /><input id="__tabbed_9_7" name="__tabbed_9" type="radio" /><input id="__tabbed_9_8" name="__tabbed_9" type="radio" /><input id="__tabbed_9_9" name="__tabbed_9" type="radio" /><input id="__tabbed_9_10" name="__tabbed_9" type="radio" /><input id="__tabbed_9_11" name="__tabbed_9" type="radio" /><input id="__tabbed_9_12" name="__tabbed_9" type="radio" /><input id="__tabbed_9_13" name="__tabbed_9" type="radio" /><input id="__tabbed_9_14" name="__tabbed_9" type="radio" /><div class="tabbed-labels"><label for="__tabbed_9_1">Python</label><label for="__tabbed_9_2">C++</label><label for="__tabbed_9_3">Java</label><label for="__tabbed_9_4">C#</label><label for="__tabbed_9_5">Go</label><label for="__tabbed_9_6">Swift</label><label for="__tabbed_9_7">JS</label><label for="__tabbed_9_8">TS</label><label for="__tabbed_9_9">Dart</label><label for="__tabbed_9_10">Rust</label><label for="__tabbed_9_11">C</label><label for="__tabbed_9_12">Kotlin</label><label for="__tabbed_9_13">Ruby</label><label for="__tabbed_9_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -4243,7 +4243,7 @@
</div>
</div>
</div>
<p>The following figure shows the time complexities of these three algorithms.</p>
<p>Figure 2-7 shows the time complexities of these three algorithms.</p>
<ul>
<li>Algorithm <code>A</code> has just one print operation, and its run time does not grow with <span class="arithmatex">\(n\)</span>. Its time complexity is considered "constant order."</li>
<li>Algorithm <code>B</code> involves a print operation looping <span class="arithmatex">\(n\)</span> times, and its run time grows linearly with <span class="arithmatex">\(n\)</span>. Its time complexity is "linear order."</li>
@ -5418,7 +5418,7 @@ O(1) &lt; O(\log n) &lt; O(n) &lt; O(n \log n) &lt; O(n^2) &lt; O(2^n) &lt; O(n!
<p><div style="height: 477px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20quadratic%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%B9%B3%E6%96%B9%E9%98%B6%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E5%BE%AA%E7%8E%AF%E6%AC%A1%E6%95%B0%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%E6%88%90%E5%B9%B3%E6%96%B9%E5%85%B3%E7%B3%BB%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20quadratic%28n%29%0A%20%20%20%20print%28%22%E5%B9%B3%E6%96%B9%E9%98%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E6%95%B0%E9%87%8F%20%3D%22,%20count%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=3&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20quadratic%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%B9%B3%E6%96%B9%E9%98%B6%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E5%BE%AA%E7%8E%AF%E6%AC%A1%E6%95%B0%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%E6%88%90%E5%B9%B3%E6%96%B9%E5%85%B3%E7%B3%BB%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20quadratic%28n%29%0A%20%20%20%20print%28%22%E5%B9%B3%E6%96%B9%E9%98%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E6%95%B0%E9%87%8F%20%3D%22,%20count%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=3&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following image compares constant order, linear order, and quadratic order time complexities.</p>
<p>Figure 2-10 compares constant order, linear order, and quadratic order time complexities.</p>
<p><a class="glightbox" href="../time_complexity.assets/time_complexity_constant_linear_quadratic.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Constant, linear, and quadratic order time complexities" class="animation-figure" src="../time_complexity.assets/time_complexity_constant_linear_quadratic.png" /></a></p>
<p align="center"> Figure 2-10 &nbsp; Constant, linear, and quadratic order time complexities </p>
@ -5727,7 +5727,7 @@ O(1) &lt; O(\log n) &lt; O(n) &lt; O(n \log n) &lt; O(n^2) &lt; O(2^n) &lt; O(n!
</details>
<h3 id="4-exponential-order-o2n">4. &nbsp; Exponential order <span class="arithmatex">\(O(2^n)\)</span><a class="headerlink" href="#4-exponential-order-o2n" title="Permanent link">&para;</a></h3>
<p>Biological "cell division" is a classic example of exponential order growth: starting with one cell, it becomes two after one division, four after two divisions, and so on, resulting in <span class="arithmatex">\(2^n\)</span> cells after <span class="arithmatex">\(n\)</span> divisions.</p>
<p>The following image and code simulate the cell division process, with a time complexity of <span class="arithmatex">\(O(2^n)\)</span>:</p>
<p>Figure 2-11 and code simulate the cell division process, with a time complexity of <span class="arithmatex">\(O(2^n)\)</span>:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="10:14"><input checked="checked" id="__tabbed_10_1" name="__tabbed_10" type="radio" /><input id="__tabbed_10_2" name="__tabbed_10" type="radio" /><input id="__tabbed_10_3" name="__tabbed_10" type="radio" /><input id="__tabbed_10_4" name="__tabbed_10" type="radio" /><input id="__tabbed_10_5" name="__tabbed_10" type="radio" /><input id="__tabbed_10_6" name="__tabbed_10" type="radio" /><input id="__tabbed_10_7" name="__tabbed_10" type="radio" /><input id="__tabbed_10_8" name="__tabbed_10" type="radio" /><input id="__tabbed_10_9" name="__tabbed_10" type="radio" /><input id="__tabbed_10_10" name="__tabbed_10" type="radio" /><input id="__tabbed_10_11" name="__tabbed_10" type="radio" /><input id="__tabbed_10_12" name="__tabbed_10" type="radio" /><input id="__tabbed_10_13" name="__tabbed_10" type="radio" /><input id="__tabbed_10_14" name="__tabbed_10" type="radio" /><div class="tabbed-labels"><label for="__tabbed_10_1">Python</label><label for="__tabbed_10_2">C++</label><label for="__tabbed_10_3">Java</label><label for="__tabbed_10_4">C#</label><label for="__tabbed_10_5">Go</label><label for="__tabbed_10_6">Swift</label><label for="__tabbed_10_7">JS</label><label for="__tabbed_10_8">TS</label><label for="__tabbed_10_9">Dart</label><label for="__tabbed_10_10">Rust</label><label for="__tabbed_10_11">C</label><label for="__tabbed_10_12">Kotlin</label><label for="__tabbed_10_13">Ruby</label><label for="__tabbed_10_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -6107,7 +6107,7 @@ O(1) &lt; O(\log n) &lt; O(n) &lt; O(n \log n) &lt; O(n^2) &lt; O(2^n) &lt; O(n!
<p>Exponential order growth is extremely rapid and is commonly seen in exhaustive search methods (brute force, backtracking, etc.). For large-scale problems, exponential order is unacceptable, often requiring dynamic programming or greedy algorithms as solutions.</p>
<h3 id="5-logarithmic-order-olog-n">5. &nbsp; Logarithmic order <span class="arithmatex">\(O(\log n)\)</span><a class="headerlink" href="#5-logarithmic-order-olog-n" title="Permanent link">&para;</a></h3>
<p>In contrast to exponential order, logarithmic order reflects situations where "the size is halved each round." Given an input data size <span class="arithmatex">\(n\)</span>, since the size is halved each round, the number of iterations is <span class="arithmatex">\(\log_2 n\)</span>, the inverse function of <span class="arithmatex">\(2^n\)</span>.</p>
<p>The following image and code simulate the "halving each round" process, with a time complexity of <span class="arithmatex">\(O(\log_2 n)\)</span>, commonly abbreviated as <span class="arithmatex">\(O(\log n)\)</span>:</p>
<p>Figure 2-12 and code simulate the "halving each round" process, with a time complexity of <span class="arithmatex">\(O(\log_2 n)\)</span>, commonly abbreviated as <span class="arithmatex">\(O(\log n)\)</span>:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="12:14"><input checked="checked" id="__tabbed_12_1" name="__tabbed_12" type="radio" /><input id="__tabbed_12_2" name="__tabbed_12" type="radio" /><input id="__tabbed_12_3" name="__tabbed_12" type="radio" /><input id="__tabbed_12_4" name="__tabbed_12" type="radio" /><input id="__tabbed_12_5" name="__tabbed_12" type="radio" /><input id="__tabbed_12_6" name="__tabbed_12" type="radio" /><input id="__tabbed_12_7" name="__tabbed_12" type="radio" /><input id="__tabbed_12_8" name="__tabbed_12" type="radio" /><input id="__tabbed_12_9" name="__tabbed_12" type="radio" /><input id="__tabbed_12_10" name="__tabbed_12" type="radio" /><input id="__tabbed_12_11" name="__tabbed_12" type="radio" /><input id="__tabbed_12_12" name="__tabbed_12" type="radio" /><input id="__tabbed_12_13" name="__tabbed_12" type="radio" /><input id="__tabbed_12_14" name="__tabbed_12" type="radio" /><div class="tabbed-labels"><label for="__tabbed_12_1">Python</label><label for="__tabbed_12_2">C++</label><label for="__tabbed_12_3">Java</label><label for="__tabbed_12_4">C#</label><label for="__tabbed_12_5">Go</label><label for="__tabbed_12_6">Swift</label><label for="__tabbed_12_7">JS</label><label for="__tabbed_12_8">TS</label><label for="__tabbed_12_9">Dart</label><label for="__tabbed_12_10">Rust</label><label for="__tabbed_12_11">C</label><label for="__tabbed_12_12">Kotlin</label><label for="__tabbed_12_13">Ruby</label><label for="__tabbed_12_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -6622,7 +6622,7 @@ O(\log_m n) = O(\log_k n / \log_k m) = O(\log_k n)
<p><div style="height: 477px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20linear_log_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%BA%BF%E6%80%A7%E5%AF%B9%E6%95%B0%E9%98%B6%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%20//%202%29%20%2B%20linear_log_recur%28n%20//%202%29%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%29%0A%20%20%20%20print%28%22%E7%BA%BF%E6%80%A7%E5%AF%B9%E6%95%B0%E9%98%B6%EF%BC%88%E9%80%92%E5%BD%92%E5%AE%9E%E7%8E%B0%EF%BC%89%E7%9A%84%E6%93%8D%E4%BD%9C%E6%95%B0%E9%87%8F%20%3D%22,%20count%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20linear_log_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%BA%BF%E6%80%A7%E5%AF%B9%E6%95%B0%E9%98%B6%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%20//%202%29%20%2B%20linear_log_recur%28n%20//%202%29%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%29%0A%20%20%20%20print%28%22%E7%BA%BF%E6%80%A7%E5%AF%B9%E6%95%B0%E9%98%B6%EF%BC%88%E9%80%92%E5%BD%92%E5%AE%9E%E7%8E%B0%EF%BC%89%E7%9A%84%E6%93%8D%E4%BD%9C%E6%95%B0%E9%87%8F%20%3D%22,%20count%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The image below demonstrates how linear-logarithmic order is generated. Each level of a binary tree has <span class="arithmatex">\(n\)</span> operations, and the tree has <span class="arithmatex">\(\log_2 n + 1\)</span> levels, resulting in a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>.</p>
<p>Figure 2-13 demonstrates how linear-logarithmic order is generated. Each level of a binary tree has <span class="arithmatex">\(n\)</span> operations, and the tree has <span class="arithmatex">\(\log_2 n + 1\)</span> levels, resulting in a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>.</p>
<p><a class="glightbox" href="../time_complexity.assets/time_complexity_logarithmic_linear.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Linear-logarithmic order time complexity" class="animation-figure" src="../time_complexity.assets/time_complexity_logarithmic_linear.png" /></a></p>
<p align="center"> Figure 2-13 &nbsp; Linear-logarithmic order time complexity </p>
@ -6632,7 +6632,7 @@ O(\log_m n) = O(\log_k n / \log_k m) = O(\log_k n)
<div class="arithmatex">\[
n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1
\]</div>
<p>Factorials are typically implemented using recursion. As shown in the image and code below, the first level splits into <span class="arithmatex">\(n\)</span> branches, the second level into <span class="arithmatex">\(n - 1\)</span> branches, and so on, stopping after the <span class="arithmatex">\(n\)</span>th level:</p>
<p>Factorials are typically implemented using recursion. As shown in the code and Figure 2-14, the first level splits into <span class="arithmatex">\(n\)</span> branches, the second level into <span class="arithmatex">\(n - 1\)</span> branches, and so on, stopping after the <span class="arithmatex">\(n\)</span>th level:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="15:14"><input checked="checked" id="__tabbed_15_1" name="__tabbed_15" type="radio" /><input id="__tabbed_15_2" name="__tabbed_15" type="radio" /><input id="__tabbed_15_3" name="__tabbed_15" type="radio" /><input id="__tabbed_15_4" name="__tabbed_15" type="radio" /><input id="__tabbed_15_5" name="__tabbed_15" type="radio" /><input id="__tabbed_15_6" name="__tabbed_15" type="radio" /><input id="__tabbed_15_7" name="__tabbed_15" type="radio" /><input id="__tabbed_15_8" name="__tabbed_15" type="radio" /><input id="__tabbed_15_9" name="__tabbed_15" type="radio" /><input id="__tabbed_15_10" name="__tabbed_15" type="radio" /><input id="__tabbed_15_11" name="__tabbed_15" type="radio" /><input id="__tabbed_15_12" name="__tabbed_15" type="radio" /><input id="__tabbed_15_13" name="__tabbed_15" type="radio" /><input id="__tabbed_15_14" name="__tabbed_15" type="radio" /><div class="tabbed-labels"><label for="__tabbed_15_1">Python</label><label for="__tabbed_15_2">C++</label><label for="__tabbed_15_3">Java</label><label for="__tabbed_15_4">C#</label><label for="__tabbed_15_5">Go</label><label for="__tabbed_15_6">Swift</label><label for="__tabbed_15_7">JS</label><label for="__tabbed_15_8">TS</label><label for="__tabbed_15_9">Dart</label><label for="__tabbed_15_10">Rust</label><label for="__tabbed_15_11">C</label><label for="__tabbed_15_12">Kotlin</label><label for="__tabbed_15_13">Ruby</label><label for="__tabbed_15_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -3647,7 +3647,7 @@
<h1 id="34-character-encoding">3.4 &nbsp; Character encoding *<a class="headerlink" href="#34-character-encoding" title="Permanent link">&para;</a></h1>
<p>In the computer system, all data is stored in binary form, and characters (represented by char) are no exception. To represent characters, we need to develop a "character set" that defines a one-to-one mapping between each character and binary numbers. With the character set, computers can convert binary numbers to characters by looking up the table.</p>
<h2 id="341-ascii-character-set">3.4.1 &nbsp; ASCII character set<a class="headerlink" href="#341-ascii-character-set" title="Permanent link">&para;</a></h2>
<p>The "ASCII code" is one of the earliest character sets, officially known as the American Standard Code for Information Interchange. It uses 7 binary digits (the lower 7 bits of a byte) to represent a character, allowing for a maximum of 128 different characters. As shown in the Figure 3-6 , ASCII includes uppercase and lowercase English letters, numbers 0 ~ 9, various punctuation marks, and certain control characters (such as newline and tab).</p>
<p>The "ASCII code" is one of the earliest character sets, officially known as the American Standard Code for Information Interchange. It uses 7 binary digits (the lower 7 bits of a byte) to represent a character, allowing for a maximum of 128 different characters. As shown in Figure 3-6, ASCII includes uppercase and lowercase English letters, numbers 0 ~ 9, various punctuation marks, and certain control characters (such as newline and tab).</p>
<p><a class="glightbox" href="../character_encoding.assets/ascii_table.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="ASCII code" class="animation-figure" src="../character_encoding.assets/ascii_table.png" /></a></p>
<p align="center"> Figure 3-6 &nbsp; ASCII code </p>
@ -3662,7 +3662,7 @@
<p>"Unicode" is referred to as "统一码" (Unified Code) in Chinese, theoretically capable of accommodating over a million characters. It aims to incorporate characters from all over the world into a single set, providing a universal character set for processing and displaying various languages and reducing the issues of garbled text due to different encoding standards.</p>
<p>Since its release in 1991, Unicode has continually expanded to include new languages and characters. As of September 2022, Unicode contains 149,186 characters, including characters, symbols, and even emojis from various languages. In the vast Unicode character set, commonly used characters occupy 2 bytes, while some rare characters may occupy 3 or even 4 bytes.</p>
<p>Unicode is a universal character set that assigns a number (called a "code point") to each character, <strong>but it does not specify how these character code points should be stored in a computer system</strong>. One might ask: How does a system interpret Unicode code points of varying lengths within a text? For example, given a 2-byte code, how does the system determine if it represents a single 2-byte character or two 1-byte characters?</p>
<p>A straightforward solution to this problem is to store all characters as equal-length encodings. As shown in the Figure 3-7 , each character in "Hello" occupies 1 byte, while each character in "算法" (algorithm) occupies 2 bytes. We could encode all characters in "Hello 算法" as 2 bytes by padding the higher bits with zeros. This method would enable the system to interpret a character every 2 bytes, recovering the content of the phrase.</p>
<p>A straightforward solution to this problem is to store all characters as equal-length encodings. As shown in Figure 3-7, each character in "Hello" occupies 1 byte, while each character in "算法" (algorithm) occupies 2 bytes. We could encode all characters in "Hello 算法" as 2 bytes by padding the higher bits with zeros. This method would enable the system to interpret a character every 2 bytes, recovering the content of the phrase.</p>
<p><a class="glightbox" href="../character_encoding.assets/unicode_hello_algo.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Unicode encoding example" class="animation-figure" src="../character_encoding.assets/unicode_hello_algo.png" /></a></p>
<p align="center"> Figure 3-7 &nbsp; Unicode encoding example </p>
@ -3674,7 +3674,7 @@
<li>For 1-byte characters, set the highest bit to <span class="arithmatex">\(0\)</span>, and the remaining 7 bits to the Unicode code point. Notably, ASCII characters occupy the first 128 code points in the Unicode set. This means that <strong>UTF-8 encoding is backward compatible with ASCII</strong>. This implies that UTF-8 can be used to parse ancient ASCII text.</li>
<li>For characters of length <span class="arithmatex">\(n\)</span> bytes (where <span class="arithmatex">\(n &gt; 1\)</span>), set the highest <span class="arithmatex">\(n\)</span> bits of the first byte to <span class="arithmatex">\(1\)</span>, and the <span class="arithmatex">\((n + 1)^{\text{th}}\)</span> bit to <span class="arithmatex">\(0\)</span>; starting from the second byte, set the highest 2 bits of each byte to <span class="arithmatex">\(10\)</span>; the rest of the bits are used to fill the Unicode code point.</li>
</ul>
<p>The Figure 3-8 shows the UTF-8 encoding for "Hello算法". It can be observed that since the highest <span class="arithmatex">\(n\)</span> bits are set to <span class="arithmatex">\(1\)</span>, the system can determine the length of the character as <span class="arithmatex">\(n\)</span> by counting the number of highest bits set to <span class="arithmatex">\(1\)</span>.</p>
<p>Figure 3-8 shows the UTF-8 encoding for "Hello算法". It can be observed that since the highest <span class="arithmatex">\(n\)</span> bits are set to <span class="arithmatex">\(1\)</span>, the system can determine the length of the character as <span class="arithmatex">\(n\)</span> by counting the number of highest bits set to <span class="arithmatex">\(1\)</span>.</p>
<p>But why set the highest 2 bits of the remaining bytes to <span class="arithmatex">\(10\)</span>? Actually, this <span class="arithmatex">\(10\)</span> serves as a kind of checksum. If the system starts parsing text from an incorrect byte, the <span class="arithmatex">\(10\)</span> at the beginning of the byte can help the system quickly detect anomalies.</p>
<p>The reason for using <span class="arithmatex">\(10\)</span> as a checksum is that, under UTF-8 encoding rules, it's impossible for the highest two bits of a character to be <span class="arithmatex">\(10\)</span>. This can be proven by contradiction: If the highest two bits of a character are <span class="arithmatex">\(10\)</span>, it indicates that the character's length is <span class="arithmatex">\(1\)</span>, corresponding to ASCII. However, the highest bit of an ASCII character should be <span class="arithmatex">\(0\)</span>, which contradicts the assumption.</p>
<p><a class="glightbox" href="../character_encoding.assets/utf-8_hello_algo.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="UTF-8 encoding example" class="animation-figure" src="../character_encoding.assets/utf-8_hello_algo.png" /></a></p>

View File

@ -3594,7 +3594,7 @@
<p>Common data structures include arrays, linked lists, stacks, queues, hash tables, trees, heaps, and graphs. They can be classified into "logical structure" and "physical structure".</p>
<h2 id="311-logical-structure-linear-and-non-linear">3.1.1 &nbsp; Logical structure: linear and non-linear<a class="headerlink" href="#311-logical-structure-linear-and-non-linear" title="Permanent link">&para;</a></h2>
<p><strong>The logical structures reveal the logical relationships between data elements</strong>. In arrays and linked lists, data are arranged in a specific sequence, demonstrating the linear relationship between data; while in trees, data are arranged hierarchically from the top down, showing the derived relationship between "ancestors" and "descendants"; and graphs are composed of nodes and edges, reflecting the intricate network relationship.</p>
<p>As shown in the Figure 3-1 , logical structures can be divided into two major categories: "linear" and "non-linear". Linear structures are more intuitive, indicating data is arranged linearly in logical relationships; non-linear structures, conversely, are arranged non-linearly.</p>
<p>As shown in Figure 3-1, logical structures can be divided into two major categories: "linear" and "non-linear". Linear structures are more intuitive, indicating data is arranged linearly in logical relationships; non-linear structures, conversely, are arranged non-linearly.</p>
<ul>
<li><strong>Linear data structures</strong>: Arrays, Linked Lists, Stacks, Queues, Hash Tables.</li>
<li><strong>Non-linear data structures</strong>: Trees, Heaps, Graphs, Hash Tables.</li>
@ -3609,8 +3609,8 @@
<li><strong>Network structures</strong>: Graphs, where elements have a many-to-many relationships.</li>
</ul>
<h2 id="312-physical-structure-contiguous-and-dispersed">3.1.2 &nbsp; Physical structure: contiguous and dispersed<a class="headerlink" href="#312-physical-structure-contiguous-and-dispersed" title="Permanent link">&para;</a></h2>
<p><strong>During the execution of an algorithm, the data being processed is stored in memory</strong>. The Figure 3-2 shows a computer memory stick where each black square is a physical memory space. We can think of memory as a vast Excel spreadsheet, with each cell capable of storing a certain amount of data.</p>
<p><strong>The system accesses the data at the target location by means of a memory address</strong>. As shown in the Figure 3-2 , the computer assigns a unique identifier to each cell in the table according to specific rules, ensuring that each memory space has a unique memory address. With these addresses, the program can access the data stored in memory.</p>
<p><strong>During the execution of an algorithm, the data being processed is stored in memory</strong>. Figure 3-2 shows a computer memory stick where each black square is a physical memory space. We can think of memory as a vast Excel spreadsheet, with each cell capable of storing a certain amount of data.</p>
<p><strong>The system accesses the data at the target location by means of a memory address</strong>. As shown in Figure 3-2, the computer assigns a unique identifier to each cell in the table according to specific rules, ensuring that each memory space has a unique memory address. With these addresses, the program can access the data stored in memory.</p>
<p><a class="glightbox" href="../classification_of_data_structure.assets/computer_memory_location.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Memory stick, memory spaces, memory addresses" class="animation-figure" src="../classification_of_data_structure.assets/computer_memory_location.png" /></a></p>
<p align="center"> Figure 3-2 &nbsp; Memory stick, memory spaces, memory addresses </p>
@ -3619,7 +3619,7 @@
<p>It's worth noting that comparing memory to an Excel spreadsheet is a simplified analogy. The actual working mechanism of memory is more complex, involving concepts like address space, memory management, cache mechanisms, virtual memory, and physical memory.</p>
</div>
<p>Memory is a shared resource for all programs. When a block of memory is occupied by one program, it cannot be simultaneously used by other programs. <strong>Therefore, considering memory resources is crucial in designing data structures and algorithms</strong>. For instance, the algorithm's peak memory usage should not exceed the remaining free memory of the system; if there is a lack of contiguous memory blocks, then the data structure chosen must be able to be stored in non-contiguous memory blocks.</p>
<p>As illustrated in the Figure 3-3 , <strong>the physical structure reflects the way data is stored in computer memory</strong> and it can be divided into contiguous space storage (arrays) and non-contiguous space storage (linked lists). The two types of physical structures exhibit complementary characteristics in terms of time efficiency and space efficiency.</p>
<p>As illustrated in Figure 3-3, <strong>the physical structure reflects the way data is stored in computer memory</strong> and it can be divided into contiguous space storage (arrays) and non-contiguous space storage (linked lists). The two types of physical structures exhibit complementary characteristics in terms of time efficiency and space efficiency.</p>
<p><a class="glightbox" href="../classification_of_data_structure.assets/classification_phisical_structure.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Contiguous space storage and dispersed space storage" class="animation-figure" src="../classification_of_data_structure.assets/classification_phisical_structure.png" /></a></p>
<p align="center"> Figure 3-3 &nbsp; Contiguous space storage and dispersed space storage </p>

View File

@ -3695,7 +3695,7 @@ b_{31} b_{30} b_{29} \ldots b_2 b_1 b_0
\]</div>
<p>Now we can answer the initial question: <strong>The representation of <code>float</code> includes an exponent bit, leading to a much larger range than <code>int</code></strong>. Based on the above calculation, the maximum positive number representable by <code>float</code> is approximately <span class="arithmatex">\(2^{254 - 127} \times (2 - 2^{-23}) \approx 3.4 \times 10^{38}\)</span>, and the minimum negative number is obtained by switching the sign bit.</p>
<p><strong>However, the trade-off for <code>float</code>'s expanded range is a sacrifice in precision</strong>. The integer type <code>int</code> uses all 32 bits to represent the number, with values evenly distributed; but due to the exponent bit, the larger the value of a <code>float</code>, the greater the difference between adjacent numbers.</p>
<p>As shown in the Table 3-2 , exponent bits <span class="arithmatex">\(\mathrm{E} = 0\)</span> and <span class="arithmatex">\(\mathrm{E} = 255\)</span> have special meanings, <strong>used to represent zero, infinity, <span class="arithmatex">\(\mathrm{NaN}\)</span>, etc.</strong></p>
<p>As shown in Table 3-2, exponent bits <span class="arithmatex">\(\mathrm{E} = 0\)</span> and <span class="arithmatex">\(\mathrm{E} = 255\)</span> have special meanings, <strong>used to represent zero, infinity, <span class="arithmatex">\(\mathrm{NaN}\)</span>, etc.</strong></p>
<p align="center"> Table 3-2 &nbsp; Meaning of exponent bits </p>
<div class="center-table">

View File

@ -3664,7 +3664,7 @@
<li>Let the index of the current tree's root node in <code>inorder</code> be denoted as <span class="arithmatex">\(m\)</span>.</li>
<li>Let the index interval of the current tree in <code>inorder</code> be denoted as <span class="arithmatex">\([l, r]\)</span>.</li>
</ul>
<p>As shown in the Table 12-1 , the above variables can represent the index of the root node in <code>preorder</code> as well as the index intervals of the subtrees in <code>inorder</code>.</p>
<p>As shown in Table 12-1, the above variables can represent the index of the root node in <code>preorder</code> as well as the index intervals of the subtrees in <code>inorder</code>.</p>
<p align="center"> Table 12-1 &nbsp; Indexes of the root node and subtrees in preorder and inorder traversals </p>
<div class="center-table">

View File

@ -3662,7 +3662,7 @@
<li><strong>Divide (partition phase)</strong>: Recursively decompose the original problem into two or more sub-problems until the smallest sub-problem is reached and the process terminates.</li>
<li><strong>Conquer (merge phase)</strong>: Starting from the smallest sub-problem with a known solution, merge the solutions of the sub-problems from bottom to top to construct the solution to the original problem.</li>
</ol>
<p>As shown in the Figure 12-1 , "merge sort" is one of the typical applications of the divide and conquer strategy.</p>
<p>As shown in Figure 12-1, "merge sort" is one of the typical applications of the divide and conquer strategy.</p>
<ol>
<li><strong>Divide</strong>: Recursively divide the original array (original problem) into two sub-arrays (sub-problems), until the sub-array has only one element (smallest sub-problem).</li>
<li><strong>Conquer</strong>: Merge the ordered sub-arrays (solutions to the sub-problems) from bottom to top to obtain an ordered original array (solution to the original problem).</li>
@ -3687,7 +3687,7 @@
<p><strong>Divide and conquer can not only effectively solve algorithm problems but often also improve algorithm efficiency</strong>. In sorting algorithms, quicksort, merge sort, and heap sort are faster than selection, bubble, and insertion sorts because they apply the divide and conquer strategy.</p>
<p>Then, we may ask: <strong>Why can divide and conquer improve algorithm efficiency, and what is the underlying logic?</strong> In other words, why are the steps of decomposing a large problem into multiple sub-problems, solving the sub-problems, and merging the solutions of the sub-problems into the solution of the original problem more efficient than directly solving the original problem? This question can be discussed from the aspects of the number of operations and parallel computation.</p>
<h3 id="1-optimization-of-operation-count">1. &nbsp; Optimization of operation count<a class="headerlink" href="#1-optimization-of-operation-count" title="Permanent link">&para;</a></h3>
<p>Taking "bubble sort" as an example, it requires <span class="arithmatex">\(O(n^2)\)</span> time to process an array of length <span class="arithmatex">\(n\)</span>. Suppose we divide the array from the midpoint into two sub-arrays as shown in the Figure 12-2 , then the division requires <span class="arithmatex">\(O(n)\)</span> time, sorting each sub-array requires <span class="arithmatex">\(O((n / 2)^2)\)</span> time, and merging the two sub-arrays requires <span class="arithmatex">\(O(n)\)</span> time, with the total time complexity being:</p>
<p>Taking "bubble sort" as an example, it requires <span class="arithmatex">\(O(n^2)\)</span> time to process an array of length <span class="arithmatex">\(n\)</span>. Suppose we divide the array from the midpoint into two sub-arrays as shown in Figure 12-2, then the division requires <span class="arithmatex">\(O(n)\)</span> time, sorting each sub-array requires <span class="arithmatex">\(O((n / 2)^2)\)</span> time, and merging the two sub-arrays requires <span class="arithmatex">\(O(n)\)</span> time, with the total time complexity being:</p>
<div class="arithmatex">\[
O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n)
\]</div>
@ -3708,7 +3708,7 @@ n(n - 4) &amp; &gt; 0
<h3 id="2-optimization-through-parallel-computation">2. &nbsp; Optimization through parallel computation<a class="headerlink" href="#2-optimization-through-parallel-computation" title="Permanent link">&para;</a></h3>
<p>We know that the sub-problems generated by divide and conquer are independent of each other, <strong>thus they can usually be solved in parallel</strong>. This means that divide and conquer can not only reduce the algorithm's time complexity, <strong>but also facilitate parallel optimization by the operating system</strong>.</p>
<p>Parallel optimization is especially effective in environments with multiple cores or processors, as the system can process multiple sub-problems simultaneously, making fuller use of computing resources and significantly reducing the overall runtime.</p>
<p>For example, in the "bucket sort" shown in the Figure 12-3 , we distribute massive data evenly across various buckets, then the sorting tasks of all buckets can be distributed to different computing units, and the results are merged after completion.</p>
<p>For example, in the "bucket sort" shown in Figure 12-3, we distribute massive data evenly across various buckets, then the sorting tasks of all buckets can be distributed to different computing units, and the results are merged after completion.</p>
<p><a class="glightbox" href="../divide_and_conquer.assets/divide_and_conquer_parallel_computing.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Bucket sort's parallel computation" class="animation-figure" src="../divide_and_conquer.assets/divide_and_conquer_parallel_computing.png" /></a></p>
<p align="center"> Figure 12-3 &nbsp; Bucket sort's parallel computation </p>

View File

@ -3612,7 +3612,7 @@
<p>In both merge sorting and building binary trees, we decompose the original problem into two subproblems, each half the size of the original problem. However, for the Tower of Hanoi, we adopt a different decomposition strategy.</p>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>Given three pillars, denoted as <code>A</code>, <code>B</code>, and <code>C</code>. Initially, pillar <code>A</code> is stacked with <span class="arithmatex">\(n\)</span> discs, arranged in order from top to bottom from smallest to largest. Our task is to move these <span class="arithmatex">\(n\)</span> discs to pillar <code>C</code>, maintaining their original order (as shown below). The following rules must be followed during the disc movement process:</p>
<p>Given three pillars, denoted as <code>A</code>, <code>B</code>, and <code>C</code>. Initially, pillar <code>A</code> is stacked with <span class="arithmatex">\(n\)</span> discs, arranged in order from top to bottom from smallest to largest. Our task is to move these <span class="arithmatex">\(n\)</span> discs to pillar <code>C</code>, maintaining their original order (as shown in Figure 12-10). The following rules must be followed during the disc movement process:</p>
<ol>
<li>A disc can only be picked up from the top of a pillar and placed on top of another pillar.</li>
<li>Only one disc can be moved at a time.</li>
@ -3624,7 +3624,7 @@
<p><strong>We denote the Tower of Hanoi of size <span class="arithmatex">\(i\)</span> as <span class="arithmatex">\(f(i)\)</span></strong>. For example, <span class="arithmatex">\(f(3)\)</span> represents the Tower of Hanoi of moving <span class="arithmatex">\(3\)</span> discs from <code>A</code> to <code>C</code>.</p>
<h3 id="1-consider-the-base-case">1. &nbsp; Consider the base case<a class="headerlink" href="#1-consider-the-base-case" title="Permanent link">&para;</a></h3>
<p>As shown below, for the problem <span class="arithmatex">\(f(1)\)</span>, i.e., when there is only one disc, we can directly move it from <code>A</code> to <code>C</code>.</p>
<p>As shown in Figure 12-11, for the problem <span class="arithmatex">\(f(1)\)</span>, i.e., when there is only one disc, we can directly move it from <code>A</code> to <code>C</code>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">&lt;1&gt;</label><label for="__tabbed_1_2">&lt;2&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -3637,7 +3637,7 @@
</div>
<p align="center"> Figure 12-11 &nbsp; Solution for a problem of size 1 </p>
<p>As shown below, for the problem <span class="arithmatex">\(f(2)\)</span>, i.e., when there are two discs, <strong>since the smaller disc must always be above the larger disc, <code>B</code> is needed to assist in the movement</strong>.</p>
<p>As shown in Figure 12-12, for the problem <span class="arithmatex">\(f(2)\)</span>, i.e., when there are two discs, <strong>since the smaller disc must always be above the larger disc, <code>B</code> is needed to assist in the movement</strong>.</p>
<ol>
<li>First, move the smaller disc from <code>A</code> to <code>B</code>.</li>
<li>Then move the larger disc from <code>A</code> to <code>C</code>.</li>
@ -3664,7 +3664,7 @@
<p>The process of solving the problem <span class="arithmatex">\(f(2)\)</span> can be summarized as: <strong>moving two discs from <code>A</code> to <code>C</code> with the help of <code>B</code></strong>. Here, <code>C</code> is called the target pillar, and <code>B</code> is called the buffer pillar.</p>
<h3 id="2-decomposition-of-subproblems">2. &nbsp; Decomposition of subproblems<a class="headerlink" href="#2-decomposition-of-subproblems" title="Permanent link">&para;</a></h3>
<p>For the problem <span class="arithmatex">\(f(3)\)</span>, i.e., when there are three discs, the situation becomes slightly more complicated.</p>
<p>Since we already know the solutions to <span class="arithmatex">\(f(1)\)</span> and <span class="arithmatex">\(f(2)\)</span>, we can think from a divide-and-conquer perspective and <strong>consider the two top discs on <code>A</code> as a unit</strong>, performing the steps shown below. This way, the three discs are successfully moved from <code>A</code> to <code>C</code>.</p>
<p>Since we already know the solutions to <span class="arithmatex">\(f(1)\)</span> and <span class="arithmatex">\(f(2)\)</span>, we can think from a divide-and-conquer perspective and <strong>consider the two top discs on <code>A</code> as a unit</strong>, performing the steps shown in Figure 12-13. This way, the three discs are successfully moved from <code>A</code> to <code>C</code>.</p>
<ol>
<li>Let <code>B</code> be the target pillar and <code>C</code> the buffer pillar, and move the two discs from <code>A</code> to <code>B</code>.</li>
<li>Move the remaining disc from <code>A</code> directly to <code>C</code>.</li>
@ -3689,7 +3689,7 @@
<p align="center"> Figure 12-13 &nbsp; Solution for a problem of size 3 </p>
<p>Essentially, <strong>we divide the problem <span class="arithmatex">\(f(3)\)</span> into two subproblems <span class="arithmatex">\(f(2)\)</span> and one subproblem <span class="arithmatex">\(f(1)\)</span></strong>. By solving these three subproblems in order, the original problem is resolved. This indicates that the subproblems are independent, and their solutions can be merged.</p>
<p>From this, we can summarize the divide-and-conquer strategy for solving the Tower of Hanoi shown in the following image: divide the original problem <span class="arithmatex">\(f(n)\)</span> into two subproblems <span class="arithmatex">\(f(n-1)\)</span> and one subproblem <span class="arithmatex">\(f(1)\)</span>, and solve these three subproblems in the following order.</p>
<p>From this, we can summarize the divide-and-conquer strategy for solving the Tower of Hanoi shown in Figure 12-14: divide the original problem <span class="arithmatex">\(f(n)\)</span> into two subproblems <span class="arithmatex">\(f(n-1)\)</span> and one subproblem <span class="arithmatex">\(f(1)\)</span>, and solve these three subproblems in the following order.</p>
<ol>
<li>Move <span class="arithmatex">\(n-1\)</span> discs with the help of <code>C</code> from <code>A</code> to <code>B</code>.</li>
<li>Move the remaining one disc directly from <code>A</code> to <code>C</code>.</li>
@ -4113,7 +4113,7 @@
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20move%28src%3A%20list%5Bint%5D,%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%22%22%22%0A%20%20%20%20%23%20%E4%BB%8E%20src%20%E9%A1%B6%E9%83%A8%E6%8B%BF%E5%87%BA%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%0A%20%20%20%20pan%20%3D%20src.pop%28%29%0A%20%20%20%20%23%20%E5%B0%86%E5%9C%86%E7%9B%98%E6%94%BE%E5%85%A5%20tar%20%E9%A1%B6%E9%83%A8%0A%20%20%20%20tar.append%28pan%29%0A%0A%0Adef%20dfs%28i%3A%20int,%20src%3A%20list%5Bint%5D,%20buf%3A%20list%5Bint%5D,%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E6%B1%89%E8%AF%BA%E5%A1%94%E9%97%AE%E9%A2%98%20f%28i%29%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%20src%20%E5%8F%AA%E5%89%A9%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E5%B0%86%E5%85%B6%E7%A7%BB%E5%88%B0%20tar%0A%20%20%20%20if%20i%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20move%28src,%20tar%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E5%AD%90%E9%97%AE%E9%A2%98%20f%28i-1%29%20%EF%BC%9A%E5%B0%86%20src%20%E9%A1%B6%E9%83%A8%20i-1%20%E4%B8%AA%E5%9C%86%E7%9B%98%E5%80%9F%E5%8A%A9%20tar%20%E7%A7%BB%E5%88%B0%20buf%0A%20%20%20%20dfs%28i%20-%201,%20src,%20tar,%20buf%29%0A%20%20%20%20%23%20%E5%AD%90%E9%97%AE%E9%A2%98%20f%281%29%20%EF%BC%9A%E5%B0%86%20src%20%E5%89%A9%E4%BD%99%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%E7%A7%BB%E5%88%B0%20tar%0A%20%20%20%20move%28src,%20tar%29%0A%20%20%20%20%23%20%E5%AD%90%E9%97%AE%E9%A2%98%20f%28i-1%29%20%EF%BC%9A%E5%B0%86%20buf%20%E9%A1%B6%E9%83%A8%20i-1%20%E4%B8%AA%E5%9C%86%E7%9B%98%E5%80%9F%E5%8A%A9%20src%20%E7%A7%BB%E5%88%B0%20tar%0A%20%20%20%20dfs%28i%20-%201,%20buf,%20src,%20tar%29%0A%0A%0Adef%20solve_hanota%28A%3A%20list%5Bint%5D,%20B%3A%20list%5Bint%5D,%20C%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E6%B1%89%E8%AF%BA%E5%A1%94%E9%97%AE%E9%A2%98%22%22%22%0A%20%20%20%20n%20%3D%20len%28A%29%0A%20%20%20%20%23%20%E5%B0%86%20A%20%E9%A1%B6%E9%83%A8%20n%20%E4%B8%AA%E5%9C%86%E7%9B%98%E5%80%9F%E5%8A%A9%20B%20%E7%A7%BB%E5%88%B0%20C%0A%20%20%20%20dfs%28n,%20A,%20B,%20C%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%97%E8%A1%A8%E5%B0%BE%E9%83%A8%E6%98%AF%E6%9F%B1%E5%AD%90%E9%A1%B6%E9%83%A8%0A%20%20%20%20A%20%3D%20%5B5,%204,%203,%202,%201%5D%0A%20%20%20%20B%20%3D%20%5B%5D%0A%20%20%20%20C%20%3D%20%5B%5D%0A%20%20%20%20print%28%22%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81%E4%B8%8B%EF%BC%9A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29%0A%0A%20%20%20%20solve_hanota%28A,%20B,%20C%29%0A%0A%20%20%20%20print%28%22%E5%9C%86%E7%9B%98%E7%A7%BB%E5%8A%A8%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%9A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=12&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20move%28src%3A%20list%5Bint%5D,%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%22%22%22%0A%20%20%20%20%23%20%E4%BB%8E%20src%20%E9%A1%B6%E9%83%A8%E6%8B%BF%E5%87%BA%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%0A%20%20%20%20pan%20%3D%20src.pop%28%29%0A%20%20%20%20%23%20%E5%B0%86%E5%9C%86%E7%9B%98%E6%94%BE%E5%85%A5%20tar%20%E9%A1%B6%E9%83%A8%0A%20%20%20%20tar.append%28pan%29%0A%0A%0Adef%20dfs%28i%3A%20int,%20src%3A%20list%5Bint%5D,%20buf%3A%20list%5Bint%5D,%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E6%B1%89%E8%AF%BA%E5%A1%94%E9%97%AE%E9%A2%98%20f%28i%29%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%20src%20%E5%8F%AA%E5%89%A9%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E5%B0%86%E5%85%B6%E7%A7%BB%E5%88%B0%20tar%0A%20%20%20%20if%20i%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20move%28src,%20tar%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E5%AD%90%E9%97%AE%E9%A2%98%20f%28i-1%29%20%EF%BC%9A%E5%B0%86%20src%20%E9%A1%B6%E9%83%A8%20i-1%20%E4%B8%AA%E5%9C%86%E7%9B%98%E5%80%9F%E5%8A%A9%20tar%20%E7%A7%BB%E5%88%B0%20buf%0A%20%20%20%20dfs%28i%20-%201,%20src,%20tar,%20buf%29%0A%20%20%20%20%23%20%E5%AD%90%E9%97%AE%E9%A2%98%20f%281%29%20%EF%BC%9A%E5%B0%86%20src%20%E5%89%A9%E4%BD%99%E4%B8%80%E4%B8%AA%E5%9C%86%E7%9B%98%E7%A7%BB%E5%88%B0%20tar%0A%20%20%20%20move%28src,%20tar%29%0A%20%20%20%20%23%20%E5%AD%90%E9%97%AE%E9%A2%98%20f%28i-1%29%20%EF%BC%9A%E5%B0%86%20buf%20%E9%A1%B6%E9%83%A8%20i-1%20%E4%B8%AA%E5%9C%86%E7%9B%98%E5%80%9F%E5%8A%A9%20src%20%E7%A7%BB%E5%88%B0%20tar%0A%20%20%20%20dfs%28i%20-%201,%20buf,%20src,%20tar%29%0A%0A%0Adef%20solve_hanota%28A%3A%20list%5Bint%5D,%20B%3A%20list%5Bint%5D,%20C%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E6%B1%82%E8%A7%A3%E6%B1%89%E8%AF%BA%E5%A1%94%E9%97%AE%E9%A2%98%22%22%22%0A%20%20%20%20n%20%3D%20len%28A%29%0A%20%20%20%20%23%20%E5%B0%86%20A%20%E9%A1%B6%E9%83%A8%20n%20%E4%B8%AA%E5%9C%86%E7%9B%98%E5%80%9F%E5%8A%A9%20B%20%E7%A7%BB%E5%88%B0%20C%0A%20%20%20%20dfs%28n,%20A,%20B,%20C%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%97%E8%A1%A8%E5%B0%BE%E9%83%A8%E6%98%AF%E6%9F%B1%E5%AD%90%E9%A1%B6%E9%83%A8%0A%20%20%20%20A%20%3D%20%5B5,%204,%203,%202,%201%5D%0A%20%20%20%20B%20%3D%20%5B%5D%0A%20%20%20%20C%20%3D%20%5B%5D%0A%20%20%20%20print%28%22%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81%E4%B8%8B%EF%BC%9A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29%0A%0A%20%20%20%20solve_hanota%28A,%20B,%20C%29%0A%0A%20%20%20%20print%28%22%E5%9C%86%E7%9B%98%E7%A7%BB%E5%8A%A8%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%9A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=12&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown below, the Tower of Hanoi forms a recursive tree with a height of <span class="arithmatex">\(n\)</span>, each node representing a subproblem, corresponding to an open <code>dfs()</code> function, <strong>thus the time complexity is <span class="arithmatex">\(O(2^n)\)</span>, and the space complexity is <span class="arithmatex">\(O(n)\)</span></strong>.</p>
<p>As shown in Figure 12-15, the Tower of Hanoi forms a recursive tree with a height of <span class="arithmatex">\(n\)</span>, each node representing a subproblem, corresponding to an open <code>dfs()</code> function, <strong>thus the time complexity is <span class="arithmatex">\(O(2^n)\)</span>, and the space complexity is <span class="arithmatex">\(O(n)\)</span></strong>.</p>
<p><a class="glightbox" href="../hanota_problem.assets/hanota_recursive_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursive tree of the Tower of Hanoi" class="animation-figure" src="../hanota_problem.assets/hanota_recursive_tree.png" /></a></p>
<p align="center"> Figure 12-15 &nbsp; Recursive tree of the Tower of Hanoi </p>

View File

@ -3604,7 +3604,7 @@
<p class="admonition-title">Minimum cost of climbing stairs</p>
<p>Given a staircase, you can step up 1 or 2 steps at a time, and each step on the staircase has a non-negative integer representing the cost you need to pay at that step. Given a non-negative integer array <span class="arithmatex">\(cost\)</span>, where <span class="arithmatex">\(cost[i]\)</span> represents the cost you need to pay at the <span class="arithmatex">\(i\)</span>-th step, <span class="arithmatex">\(cost[0]\)</span> is the ground (starting point). What is the minimum cost required to reach the top?</p>
</div>
<p>As shown in the Figure 14-6 , if the costs of the 1<sup>st</sup>, 2<sup>nd</sup>, and 3<sup>rd</sup> steps are <span class="arithmatex">\(1\)</span>, <span class="arithmatex">\(10\)</span>, and <span class="arithmatex">\(1\)</span> respectively, then the minimum cost to climb to the 3<sup>rd</sup> step from the ground is <span class="arithmatex">\(2\)</span>.</p>
<p>As shown in Figure 14-6, if the costs of the 1<sup>st</sup>, 2<sup>nd</sup>, and 3<sup>rd</sup> steps are <span class="arithmatex">\(1\)</span>, <span class="arithmatex">\(10\)</span>, and <span class="arithmatex">\(1\)</span> respectively, then the minimum cost to climb to the 3<sup>rd</sup> step from the ground is <span class="arithmatex">\(2\)</span>.</p>
<p><a class="glightbox" href="../dp_problem_features.assets/min_cost_cs_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Minimum cost to climb to the 3rd step" class="animation-figure" src="../dp_problem_features.assets/min_cost_cs_example.png" /></a></p>
<p align="center"> Figure 14-6 &nbsp; Minimum cost to climb to the 3rd step </p>
@ -3886,7 +3886,7 @@ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20min_cost_climbing_stairs_dp%28cost%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%E6%9C%80%E5%B0%8F%E4%BB%A3%E4%BB%B7%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n%20%3D%20len%28cost%29%20-%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20cost%5Bn%5D%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%20%3D%20%5B0%5D%20*%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81%EF%BC%9A%E9%A2%84%E8%AE%BE%E6%9C%80%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%5B1%5D,%20dp%5B2%5D%20%3D%20cost%5B1%5D,%20cost%5B2%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E4%BB%8E%E8%BE%83%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E9%80%90%E6%AD%A5%E6%B1%82%E8%A7%A3%E8%BE%83%E5%A4%A7%E5%AD%90%E9%97%AE%E9%A2%98%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20min%28dp%5Bi%20-%201%5D,%20dp%5Bi%20-%202%5D%29%20%2B%20cost%5Bi%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20cost%20%3D%20%5B0,%201,%2010,%201,%201,%201,%2010,%201,%201,%2010,%201%5D%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%A5%BC%E6%A2%AF%E7%9A%84%E4%BB%A3%E4%BB%B7%E5%88%97%E8%A1%A8%E4%B8%BA%20%7Bcost%7D%22%29%0A%0A%20%20%20%20res%20%3D%20min_cost_climbing_stairs_dp%28cost%29%0A%20%20%20%20print%28f%22%E7%88%AC%E5%AE%8C%E6%A5%BC%E6%A2%AF%E7%9A%84%E6%9C%80%E4%BD%8E%E4%BB%A3%E4%BB%B7%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20min_cost_climbing_stairs_dp%28cost%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%E6%9C%80%E5%B0%8F%E4%BB%A3%E4%BB%B7%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n%20%3D%20len%28cost%29%20-%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20cost%5Bn%5D%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%20%3D%20%5B0%5D%20*%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81%EF%BC%9A%E9%A2%84%E8%AE%BE%E6%9C%80%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%5B1%5D,%20dp%5B2%5D%20%3D%20cost%5B1%5D,%20cost%5B2%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E4%BB%8E%E8%BE%83%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E9%80%90%E6%AD%A5%E6%B1%82%E8%A7%A3%E8%BE%83%E5%A4%A7%E5%AD%90%E9%97%AE%E9%A2%98%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20min%28dp%5Bi%20-%201%5D,%20dp%5Bi%20-%202%5D%29%20%2B%20cost%5Bi%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20cost%20%3D%20%5B0,%201,%2010,%201,%201,%201,%2010,%201,%201,%2010,%201%5D%0A%20%20%20%20print%28f%22%E8%BE%93%E5%85%A5%E6%A5%BC%E6%A2%AF%E7%9A%84%E4%BB%A3%E4%BB%B7%E5%88%97%E8%A1%A8%E4%B8%BA%20%7Bcost%7D%22%29%0A%0A%20%20%20%20res%20%3D%20min_cost_climbing_stairs_dp%28cost%29%0A%20%20%20%20print%28f%22%E7%88%AC%E5%AE%8C%E6%A5%BC%E6%A2%AF%E7%9A%84%E6%9C%80%E4%BD%8E%E4%BB%A3%E4%BB%B7%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The Figure 14-7 shows the dynamic programming process for the above code.</p>
<p>Figure 14-7 shows the dynamic programming process for the above code.</p>
<p><a class="glightbox" href="../dp_problem_features.assets/min_cost_cs_dp.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Dynamic programming process for minimum cost of climbing stairs" class="animation-figure" src="../dp_problem_features.assets/min_cost_cs_dp.png" /></a></p>
<p align="center"> Figure 14-7 &nbsp; Dynamic programming process for minimum cost of climbing stairs </p>
@ -4131,7 +4131,7 @@ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]
<p class="admonition-title">Stair climbing with constraints</p>
<p>Given a staircase with <span class="arithmatex">\(n\)</span> steps, you can go up 1 or 2 steps each time, <strong>but you cannot jump 1 step twice in a row</strong>. How many ways are there to climb to the top?</p>
</div>
<p>As shown in the Figure 14-8 , there are only 2 feasible options for climbing to the 3<sup>rd</sup> step, among which the option of jumping 1 step three times in a row does not meet the constraint condition and is therefore discarded.</p>
<p>As shown in Figure 14-8, there are only 2 feasible options for climbing to the 3<sup>rd</sup> step, among which the option of jumping 1 step three times in a row does not meet the constraint condition and is therefore discarded.</p>
<p><a class="glightbox" href="../dp_problem_features.assets/climbing_stairs_constraint_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Number of feasible options for climbing to the 3rd step with constraints" class="animation-figure" src="../dp_problem_features.assets/climbing_stairs_constraint_example.png" /></a></p>
<p align="center"> Figure 14-8 &nbsp; Number of feasible options for climbing to the 3rd step with constraints </p>
@ -4142,7 +4142,7 @@ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]
<li>When the last round was a jump of 1 step, the round before last could only choose to jump 2 steps, that is, <span class="arithmatex">\(dp[i, 1]\)</span> can only be transferred from <span class="arithmatex">\(dp[i-1, 2]\)</span>.</li>
<li>When the last round was a jump of 2 steps, the round before last could choose to jump 1 step or 2 steps, that is, <span class="arithmatex">\(dp[i, 2]\)</span> can be transferred from <span class="arithmatex">\(dp[i-2, 1]\)</span> or <span class="arithmatex">\(dp[i-2, 2]\)</span>.</li>
</ul>
<p>As shown in the Figure 14-9 , <span class="arithmatex">\(dp[i, j]\)</span> represents the number of solutions for state <span class="arithmatex">\([i, j]\)</span>. At this point, the state transition equation is:</p>
<p>As shown in Figure 14-9, <span class="arithmatex">\(dp[i, j]\)</span> represents the number of solutions for state <span class="arithmatex">\([i, j]\)</span>. At this point, the state transition equation is:</p>
<div class="arithmatex">\[
\begin{cases}
dp[i, 1] = dp[i-1, 2] \\

View File

@ -3702,14 +3702,14 @@
<p class="admonition-title">Question</p>
<p>Given an <span class="arithmatex">\(n \times m\)</span> two-dimensional grid <code>grid</code>, each cell in the grid contains a non-negative integer representing the cost of that cell. The robot starts from the top-left cell and can only move down or right at each step until it reaches the bottom-right cell. Return the minimum path sum from the top-left to the bottom-right.</p>
</div>
<p>The following figure shows an example, where the given grid's minimum path sum is <span class="arithmatex">\(13\)</span>.</p>
<p>Figure 14-10 shows an example, where the given grid's minimum path sum is <span class="arithmatex">\(13\)</span>.</p>
<p><a class="glightbox" href="../dp_solution_pipeline.assets/min_path_sum_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Minimum Path Sum Example Data" class="animation-figure" src="../dp_solution_pipeline.assets/min_path_sum_example.png" /></a></p>
<p align="center"> Figure 14-10 &nbsp; Minimum Path Sum Example Data </p>
<p><strong>First step: Think about each round of decisions, define the state, and thereby obtain the <span class="arithmatex">\(dp\)</span> table</strong></p>
<p>Each round of decisions in this problem is to move one step down or right from the current cell. Suppose the row and column indices of the current cell are <span class="arithmatex">\([i, j]\)</span>, then after moving down or right, the indices become <span class="arithmatex">\([i+1, j]\)</span> or <span class="arithmatex">\([i, j+1]\)</span>. Therefore, the state should include two variables: the row index and the column index, denoted as <span class="arithmatex">\([i, j]\)</span>.</p>
<p>The state <span class="arithmatex">\([i, j]\)</span> corresponds to the subproblem: the minimum path sum from the starting point <span class="arithmatex">\([0, 0]\)</span> to <span class="arithmatex">\([i, j]\)</span>, denoted as <span class="arithmatex">\(dp[i, j]\)</span>.</p>
<p>Thus, we obtain the two-dimensional <span class="arithmatex">\(dp\)</span> matrix shown below, whose size is the same as the input grid <span class="arithmatex">\(grid\)</span>.</p>
<p>Thus, we obtain the two-dimensional <span class="arithmatex">\(dp\)</span> matrix shown in Figure 14-11, whose size is the same as the input grid <span class="arithmatex">\(grid\)</span>.</p>
<p><a class="glightbox" href="../dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="State definition and DP table" class="animation-figure" src="../dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png" /></a></p>
<p align="center"> Figure 14-11 &nbsp; State definition and DP table </p>
@ -3720,7 +3720,7 @@
</div>
<p><strong>Second step: Identify the optimal substructure, then derive the state transition equation</strong></p>
<p>For the state <span class="arithmatex">\([i, j]\)</span>, it can only be derived from the cell above <span class="arithmatex">\([i-1, j]\)</span> or the cell to the left <span class="arithmatex">\([i, j-1]\)</span>. Therefore, the optimal substructure is: the minimum path sum to reach <span class="arithmatex">\([i, j]\)</span> is determined by the smaller of the minimum path sums of <span class="arithmatex">\([i, j-1]\)</span> and <span class="arithmatex">\([i-1, j]\)</span>.</p>
<p>Based on the above analysis, the state transition equation shown in the following figure can be derived:</p>
<p>Based on the above analysis, the state transition equation shown in Figure 14-12 can be derived:</p>
<div class="arithmatex">\[
dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]
\]</div>
@ -3734,7 +3734,7 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]
</div>
<p><strong>Third step: Determine boundary conditions and state transition order</strong></p>
<p>In this problem, the states in the first row can only come from the states to their left, and the states in the first column can only come from the states above them, so the first row <span class="arithmatex">\(i = 0\)</span> and the first column <span class="arithmatex">\(j = 0\)</span> are the boundary conditions.</p>
<p>As shown in the Figure 14-13 , since each cell is derived from the cell to its left and the cell above it, we use loops to traverse the matrix, the outer loop iterating over the rows and the inner loop iterating over the columns.</p>
<p>As shown in Figure 14-13, since each cell is derived from the cell to its left and the cell above it, we use loops to traverse the matrix, the outer loop iterating over the rows and the inner loop iterating over the columns.</p>
<p><a class="glightbox" href="../dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Boundary conditions and state transition order" class="animation-figure" src="../dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png" /></a></p>
<p align="center"> Figure 14-13 &nbsp; Boundary conditions and state transition order </p>
@ -4015,7 +4015,7 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs%28grid%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20j%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%EF%BC%9A%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E4%B8%BA%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%8D%95%E5%85%83%E6%A0%BC%EF%BC%8C%E5%88%99%E7%BB%88%E6%AD%A2%E6%90%9C%E7%B4%A2%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%8B%A5%E8%A1%8C%E5%88%97%E7%B4%A2%E5%BC%95%E8%B6%8A%E7%95%8C%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%20%2B%E2%88%9E%20%E4%BB%A3%E4%BB%B7%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E8%AE%A1%E7%AE%97%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%20%28i-1,%20j%29%20%E5%92%8C%20%28i,%20j-1%29%20%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20up%20%3D%20min_path_sum_dfs%28grid,%20i%20-%201,%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs%28grid,%20i,%20j%20-%201%29%0A%20%20%20%20%23%20%E8%BF%94%E5%9B%9E%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%20%28i,%20j%29%20%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20return%20min%28left,%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%0A%20%20%20%20res%20%3D%20min_path_sum_dfs%28grid,%20n%20-%201,%20m%20-%201%29%0A%20%20%20%20print%28f%22%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%9A%84%E5%81%9A%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs%28grid%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20j%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%EF%BC%9A%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E4%B8%BA%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%8D%95%E5%85%83%E6%A0%BC%EF%BC%8C%E5%88%99%E7%BB%88%E6%AD%A2%E6%90%9C%E7%B4%A2%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%8B%A5%E8%A1%8C%E5%88%97%E7%B4%A2%E5%BC%95%E8%B6%8A%E7%95%8C%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%20%2B%E2%88%9E%20%E4%BB%A3%E4%BB%B7%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E8%AE%A1%E7%AE%97%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%20%28i-1,%20j%29%20%E5%92%8C%20%28i,%20j-1%29%20%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20up%20%3D%20min_path_sum_dfs%28grid,%20i%20-%201,%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs%28grid,%20i,%20j%20-%201%29%0A%20%20%20%20%23%20%E8%BF%94%E5%9B%9E%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%20%28i,%20j%29%20%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20return%20min%28left,%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%0A%20%20%20%20res%20%3D%20min_path_sum_dfs%28grid,%20n%20-%201,%20m%20-%201%29%0A%20%20%20%20print%28f%22%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%9A%84%E5%81%9A%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following figure shows the recursive tree rooted at <span class="arithmatex">\(dp[2, 1]\)</span>, which includes some overlapping subproblems, the number of which increases sharply as the size of the grid <code>grid</code> increases.</p>
<p>Figure 14-14 shows the recursive tree rooted at <span class="arithmatex">\(dp[2, 1]\)</span>, which includes some overlapping subproblems, the number of which increases sharply as the size of the grid <code>grid</code> increases.</p>
<p>Essentially, the reason for overlapping subproblems is: <strong>there are multiple paths to reach a certain cell from the top-left corner</strong>.</p>
<p><a class="glightbox" href="../dp_solution_pipeline.assets/min_path_sum_dfs.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Brute-force search recursive tree" class="animation-figure" src="../dp_solution_pipeline.assets/min_path_sum_dfs.png" /></a></p>
<p align="center"> Figure 14-14 &nbsp; Brute-force search recursive tree </p>
@ -4358,7 +4358,7 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs_mem%28%0A%20%20%20%20grid%3A%20list%5Blist%5Bint%5D%5D,%20mem%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20j%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%EF%BC%9A%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E4%B8%BA%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%8D%95%E5%85%83%E6%A0%BC%EF%BC%8C%E5%88%99%E7%BB%88%E6%AD%A2%E6%90%9C%E7%B4%A2%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%8B%A5%E8%A1%8C%E5%88%97%E7%B4%A2%E5%BC%95%E8%B6%8A%E7%95%8C%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%20%2B%E2%88%9E%20%E4%BB%A3%E4%BB%B7%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E6%9C%89%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%0A%20%20%20%20if%20mem%5Bi%5D%5Bj%5D%20!%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%20%20%20%20%23%20%E5%B7%A6%E8%BE%B9%E5%92%8C%E4%B8%8A%E8%BE%B9%E5%8D%95%E5%85%83%E6%A0%BC%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20up%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20i%20-%201,%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20i,%20j%20-%201%29%0A%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%E5%B9%B6%E8%BF%94%E5%9B%9E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%20%28i,%20j%29%20%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20mem%5Bi%5D%5Bj%5D%20%3D%20min%28left,%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%23%20%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20*%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20res%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20n%20-%201,%20m%20-%201%29%0A%20%20%20%20print%28f%22%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%9A%84%E5%81%9A%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs_mem%28%0A%20%20%20%20grid%3A%20list%5Blist%5Bint%5D%5D,%20mem%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20j%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%EF%BC%9A%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E4%B8%BA%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%8D%95%E5%85%83%E6%A0%BC%EF%BC%8C%E5%88%99%E7%BB%88%E6%AD%A2%E6%90%9C%E7%B4%A2%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%8B%A5%E8%A1%8C%E5%88%97%E7%B4%A2%E5%BC%95%E8%B6%8A%E7%95%8C%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%20%2B%E2%88%9E%20%E4%BB%A3%E4%BB%B7%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E6%9C%89%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%0A%20%20%20%20if%20mem%5Bi%5D%5Bj%5D%20!%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%20%20%20%20%23%20%E5%B7%A6%E8%BE%B9%E5%92%8C%E4%B8%8A%E8%BE%B9%E5%8D%95%E5%85%83%E6%A0%BC%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20up%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20i%20-%201,%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20i,%20j%20-%201%29%0A%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%E5%B9%B6%E8%BF%94%E5%9B%9E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%20%28i,%20j%29%20%E7%9A%84%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E4%BB%A3%E4%BB%B7%0A%20%20%20%20mem%5Bi%5D%5Bj%5D%20%3D%20min%28left,%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%23%20%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20*%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20res%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20n%20-%201,%20m%20-%201%29%0A%20%20%20%20print%28f%22%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%9A%84%E5%81%9A%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=16&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown in the Figure 14-15 , after introducing memoization, all subproblem solutions only need to be calculated once, so the time complexity depends on the total number of states, i.e., the grid size <span class="arithmatex">\(O(nm)\)</span>.</p>
<p>As shown in Figure 14-15, after introducing memoization, all subproblem solutions only need to be calculated once, so the time complexity depends on the total number of states, i.e., the grid size <span class="arithmatex">\(O(nm)\)</span>.</p>
<p><a class="glightbox" href="../dp_solution_pipeline.assets/min_path_sum_dfs_mem.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Memoized search recursive tree" class="animation-figure" src="../dp_solution_pipeline.assets/min_path_sum_dfs_mem.png" /></a></p>
<p align="center"> Figure 14-15 &nbsp; Memoized search recursive tree </p>
@ -4716,7 +4716,7 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dp%28grid%3A%20list%5Blist%5Bint%5D%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20*%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20dp%5B0%5D%5B0%5D%20%3D%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E8%A1%8C%0A%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20dp%5B0%5D%5Bj%20-%201%5D%20%2B%20grid%5B0%5D%5Bj%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20dp%5Bi%20-%201%5D%5B0%5D%20%2B%20grid%5Bi%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E5%85%B6%E4%BD%99%E8%A1%8C%E5%92%8C%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D,%20dp%5Bi%20-%201%5D%5Bj%5D%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20dp%5Bn%20-%201%5D%5Bm%20-%201%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%0A%20%20%20%20res%20%3D%20min_path_sum_dp%28grid%29%0A%20%20%20%20print%28f%22%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%9A%84%E5%81%9A%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dp%28grid%3A%20list%5Blist%5Bint%5D%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20*%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20dp%5B0%5D%5B0%5D%20%3D%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E8%A1%8C%0A%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20dp%5B0%5D%5Bj%20-%201%5D%20%2B%20grid%5B0%5D%5Bj%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20dp%5Bi%20-%201%5D%5B0%5D%20%2B%20grid%5Bi%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E5%85%B6%E4%BD%99%E8%A1%8C%E5%92%8C%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D,%20dp%5Bi%20-%201%5D%5Bj%5D%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20dp%5Bn%20-%201%5D%5Bm%20-%201%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%0A%20%20%20%20res%20%3D%20min_path_sum_dp%28grid%29%0A%20%20%20%20print%28f%22%E4%BB%8E%E5%B7%A6%E4%B8%8A%E8%A7%92%E5%88%B0%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%9A%84%E5%81%9A%E5%B0%8F%E8%B7%AF%E5%BE%84%E5%92%8C%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following figures show the state transition process of the minimum path sum, traversing the entire grid, <strong>thus the time complexity is <span class="arithmatex">\(O(nm)\)</span></strong>.</p>
<p>Figure 14-16 show the state transition process of the minimum path sum, traversing the entire grid, <strong>thus the time complexity is <span class="arithmatex">\(O(nm)\)</span></strong>.</p>
<p>The array <code>dp</code> is of size <span class="arithmatex">\(n \times m\)</span>, <strong>therefore the space complexity is <span class="arithmatex">\(O(nm)\)</span></strong>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:12"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><input id="__tabbed_4_6" name="__tabbed_4" type="radio" /><input id="__tabbed_4_7" name="__tabbed_4" type="radio" /><input id="__tabbed_4_8" name="__tabbed_4" type="radio" /><input id="__tabbed_4_9" name="__tabbed_4" type="radio" /><input id="__tabbed_4_10" name="__tabbed_4" type="radio" /><input id="__tabbed_4_11" name="__tabbed_4" type="radio" /><input id="__tabbed_4_12" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">&lt;1&gt;</label><label for="__tabbed_4_2">&lt;2&gt;</label><label for="__tabbed_4_3">&lt;3&gt;</label><label for="__tabbed_4_4">&lt;4&gt;</label><label for="__tabbed_4_5">&lt;5&gt;</label><label for="__tabbed_4_6">&lt;6&gt;</label><label for="__tabbed_4_7">&lt;7&gt;</label><label for="__tabbed_4_8">&lt;8&gt;</label><label for="__tabbed_4_9">&lt;9&gt;</label><label for="__tabbed_4_10">&lt;10&gt;</label><label for="__tabbed_4_11">&lt;11&gt;</label><label for="__tabbed_4_12">&lt;12&gt;</label></div>
<div class="tabbed-content">

View File

@ -3615,12 +3615,12 @@
<p>Given two strings <span class="arithmatex">\(s\)</span> and <span class="arithmatex">\(t\)</span>, return the minimum number of edits required to transform <span class="arithmatex">\(s\)</span> into <span class="arithmatex">\(t\)</span>.</p>
<p>You can perform three types of edits on a string: insert a character, delete a character, or replace a character with any other character.</p>
</div>
<p>As shown in the Figure 14-27 , transforming <code>kitten</code> into <code>sitting</code> requires 3 edits, including 2 replacements and 1 insertion; transforming <code>hello</code> into <code>algo</code> requires 3 steps, including 2 replacements and 1 deletion.</p>
<p>As shown in Figure 14-27, transforming <code>kitten</code> into <code>sitting</code> requires 3 edits, including 2 replacements and 1 insertion; transforming <code>hello</code> into <code>algo</code> requires 3 steps, including 2 replacements and 1 deletion.</p>
<p><a class="glightbox" href="../edit_distance_problem.assets/edit_distance_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example data of edit distance" class="animation-figure" src="../edit_distance_problem.assets/edit_distance_example.png" /></a></p>
<p align="center"> Figure 14-27 &nbsp; Example data of edit distance </p>
<p><strong>The edit distance problem can naturally be explained with a decision tree model</strong>. Strings correspond to tree nodes, and a round of decision (an edit operation) corresponds to an edge of the tree.</p>
<p>As shown in the Figure 14-28 , with unrestricted operations, each node can derive many edges, each corresponding to one operation, meaning there are many possible paths to transform <code>hello</code> into <code>algo</code>.</p>
<p>As shown in Figure 14-28, with unrestricted operations, each node can derive many edges, each corresponding to one operation, meaning there are many possible paths to transform <code>hello</code> into <code>algo</code>.</p>
<p>From the perspective of the decision tree, the goal of this problem is to find the shortest path between the node <code>hello</code> and the node <code>algo</code>.</p>
<p><a class="glightbox" href="../edit_distance_problem.assets/edit_distance_decision_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Edit distance problem represented based on decision tree model" class="animation-figure" src="../edit_distance_problem.assets/edit_distance_decision_tree.png" /></a></p>
<p align="center"> Figure 14-28 &nbsp; Edit distance problem represented based on decision tree model </p>
@ -3637,7 +3637,7 @@
<p>State <span class="arithmatex">\([i, j]\)</span> corresponds to the subproblem: <strong>The minimum number of edits required to change the first <span class="arithmatex">\(i\)</span> characters of <span class="arithmatex">\(s\)</span> into the first <span class="arithmatex">\(j\)</span> characters of <span class="arithmatex">\(t\)</span></strong>.</p>
<p>From this, we obtain a two-dimensional <span class="arithmatex">\(dp\)</span> table of size <span class="arithmatex">\((i+1) \times (j+1)\)</span>.</p>
<p><strong>Step two: Identify the optimal substructure and then derive the state transition equation</strong></p>
<p>Consider the subproblem <span class="arithmatex">\(dp[i, j]\)</span>, whose corresponding tail characters of the two strings are <span class="arithmatex">\(s[i-1]\)</span> and <span class="arithmatex">\(t[j-1]\)</span>, which can be divided into three scenarios as shown below.</p>
<p>Consider the subproblem <span class="arithmatex">\(dp[i, j]\)</span>, whose corresponding tail characters of the two strings are <span class="arithmatex">\(s[i-1]\)</span> and <span class="arithmatex">\(t[j-1]\)</span>, which can be divided into three scenarios as shown in Figure 14-29.</p>
<ol>
<li>Add <span class="arithmatex">\(t[j-1]\)</span> after <span class="arithmatex">\(s[i-1]\)</span>, then the remaining subproblem is <span class="arithmatex">\(dp[i, j-1]\)</span>.</li>
<li>Delete <span class="arithmatex">\(s[i-1]\)</span>, then the remaining subproblem is <span class="arithmatex">\(dp[i-1, j]\)</span>.</li>
@ -4050,7 +4050,7 @@ dp[i, j] = dp[i-1, j-1]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20edit_distance_dp%28s%3A%20str,%20t%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%BC%96%E8%BE%91%E8%B7%9D%E7%A6%BB%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20*%20%28m%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E8%A1%8C%E9%A6%96%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20i%0A%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20j%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E5%85%B6%E4%BD%99%E8%A1%8C%E5%92%8C%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20s%5Bi%20-%201%5D%20%3D%3D%20t%5Bj%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8B%A5%E4%B8%A4%E5%AD%97%E7%AC%A6%E7%9B%B8%E7%AD%89%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%B7%B3%E8%BF%87%E6%AD%A4%E4%B8%A4%E5%AD%97%E7%AC%A6%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%B0%91%E7%BC%96%E8%BE%91%E6%AD%A5%E6%95%B0%20%3D%20%E6%8F%92%E5%85%A5%E3%80%81%E5%88%A0%E9%99%A4%E3%80%81%E6%9B%BF%E6%8D%A2%E8%BF%99%E4%B8%89%E7%A7%8D%E6%93%8D%E4%BD%9C%E7%9A%84%E6%9C%80%E5%B0%91%E7%BC%96%E8%BE%91%E6%AD%A5%E6%95%B0%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D,%20dp%5Bi%20-%201%5D%5Bj%5D,%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%29%20%2B%201%0A%20%20%20%20return%20dp%5Bn%5D%5Bm%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20s%20%3D%20%22bag%22%0A%20%20%20%20t%20%3D%20%22pack%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%0A%20%20%20%20%23%20%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%0A%20%20%20%20res%20%3D%20edit_distance_dp%28s,%20t%29%0A%20%20%20%20print%28f%22%E5%B0%86%20%7Bs%7D%20%E6%9B%B4%E6%94%B9%E4%B8%BA%20%7Bt%7D%20%E6%9C%80%E5%B0%91%E9%9C%80%E8%A6%81%E7%BC%96%E8%BE%91%20%7Bres%7D%20%E6%AD%A5%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20edit_distance_dp%28s%3A%20str,%20t%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%BC%96%E8%BE%91%E8%B7%9D%E7%A6%BB%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20*%20%28m%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E8%A1%8C%E9%A6%96%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20i%0A%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20j%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E5%85%B6%E4%BD%99%E8%A1%8C%E5%92%8C%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20s%5Bi%20-%201%5D%20%3D%3D%20t%5Bj%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8B%A5%E4%B8%A4%E5%AD%97%E7%AC%A6%E7%9B%B8%E7%AD%89%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%B7%B3%E8%BF%87%E6%AD%A4%E4%B8%A4%E5%AD%97%E7%AC%A6%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%B0%91%E7%BC%96%E8%BE%91%E6%AD%A5%E6%95%B0%20%3D%20%E6%8F%92%E5%85%A5%E3%80%81%E5%88%A0%E9%99%A4%E3%80%81%E6%9B%BF%E6%8D%A2%E8%BF%99%E4%B8%89%E7%A7%8D%E6%93%8D%E4%BD%9C%E7%9A%84%E6%9C%80%E5%B0%91%E7%BC%96%E8%BE%91%E6%AD%A5%E6%95%B0%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D,%20dp%5Bi%20-%201%5D%5Bj%5D,%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%29%20%2B%201%0A%20%20%20%20return%20dp%5Bn%5D%5Bm%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20s%20%3D%20%22bag%22%0A%20%20%20%20t%20%3D%20%22pack%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%0A%20%20%20%20%23%20%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%0A%20%20%20%20res%20%3D%20edit_distance_dp%28s,%20t%29%0A%20%20%20%20print%28f%22%E5%B0%86%20%7Bs%7D%20%E6%9B%B4%E6%94%B9%E4%B8%BA%20%7Bt%7D%20%E6%9C%80%E5%B0%91%E9%9C%80%E8%A6%81%E7%BC%96%E8%BE%91%20%7Bres%7D%20%E6%AD%A5%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=6&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown below, the process of state transition in the edit distance problem is very similar to that in the knapsack problem, which can be seen as filling a two-dimensional grid.</p>
<p>As shown in Figure 14-30, the process of state transition in the edit distance problem is very similar to that in the knapsack problem, which can be seen as filling a two-dimensional grid.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:15"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><input id="__tabbed_2_7" name="__tabbed_2" type="radio" /><input id="__tabbed_2_8" name="__tabbed_2" type="radio" /><input id="__tabbed_2_9" name="__tabbed_2" type="radio" /><input id="__tabbed_2_10" name="__tabbed_2" type="radio" /><input id="__tabbed_2_11" name="__tabbed_2" type="radio" /><input id="__tabbed_2_12" name="__tabbed_2" type="radio" /><input id="__tabbed_2_13" name="__tabbed_2" type="radio" /><input id="__tabbed_2_14" name="__tabbed_2" type="radio" /><input id="__tabbed_2_15" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">&lt;1&gt;</label><label for="__tabbed_2_2">&lt;2&gt;</label><label for="__tabbed_2_3">&lt;3&gt;</label><label for="__tabbed_2_4">&lt;4&gt;</label><label for="__tabbed_2_5">&lt;5&gt;</label><label for="__tabbed_2_6">&lt;6&gt;</label><label for="__tabbed_2_7">&lt;7&gt;</label><label for="__tabbed_2_8">&lt;8&gt;</label><label for="__tabbed_2_9">&lt;9&gt;</label><label for="__tabbed_2_10">&lt;10&gt;</label><label for="__tabbed_2_11">&lt;11&gt;</label><label for="__tabbed_2_12">&lt;12&gt;</label><label for="__tabbed_2_13">&lt;13&gt;</label><label for="__tabbed_2_14">&lt;14&gt;</label><label for="__tabbed_2_15">&lt;15&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -3633,7 +3633,7 @@
<p class="admonition-title">Climbing stairs</p>
<p>Given a staircase with <span class="arithmatex">\(n\)</span> steps, where you can climb <span class="arithmatex">\(1\)</span> or <span class="arithmatex">\(2\)</span> steps at a time, how many different ways are there to reach the top?</p>
</div>
<p>As shown in the Figure 14-1 , there are <span class="arithmatex">\(3\)</span> ways to reach the top of a <span class="arithmatex">\(3\)</span>-step staircase.</p>
<p>As shown in Figure 14-1, there are <span class="arithmatex">\(3\)</span> ways to reach the top of a <span class="arithmatex">\(3\)</span>-step staircase.</p>
<p><a class="glightbox" href="../intro_to_dynamic_programming.assets/climbing_stairs_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Number of ways to reach the 3rd step" class="animation-figure" src="../intro_to_dynamic_programming.assets/climbing_stairs_example.png" /></a></p>
<p align="center"> Figure 14-1 &nbsp; Number of ways to reach the 3rd step </p>
@ -4043,7 +4043,7 @@ dp[i-1], dp[i-2], \dots, dp[2], dp[1]
<div class="arithmatex">\[
dp[i] = dp[i-1] + dp[i-2]
\]</div>
<p>This means that in the stair climbing problem, there is a recursive relationship between the subproblems, <strong>the solution to the original problem can be constructed from the solutions to the subproblems</strong>. The following image shows this recursive relationship.</p>
<p>This means that in the stair climbing problem, there is a recursive relationship between the subproblems, <strong>the solution to the original problem can be constructed from the solutions to the subproblems</strong>. Figure 14-2 shows this recursive relationship.</p>
<p><a class="glightbox" href="../intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursive relationship of solution counts" class="animation-figure" src="../intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png" /></a></p>
<p align="center"> Figure 14-2 &nbsp; Recursive relationship of solution counts </p>
@ -4283,11 +4283,11 @@ dp[i] = dp[i-1] + dp[i-2]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20dfs%28i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%B2%E7%9F%A5%20dp%5B1%5D%20%E5%92%8C%20dp%5B2%5D%20%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B9%8B%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201%29%20%2B%20dfs%28i%20-%202%29%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%EF%BC%9A%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20return%20dfs%28n%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs%28n%29%0A%20%20%20%20print%28f%22%E7%88%AC%20%7Bn%7D%20%E9%98%B6%E6%A5%BC%E6%A2%AF%E5%85%B1%E6%9C%89%20%7Bres%7D%20%E7%A7%8D%E6%96%B9%E6%A1%88%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20dfs%28i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%B2%E7%9F%A5%20dp%5B1%5D%20%E5%92%8C%20dp%5B2%5D%20%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B9%8B%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201%29%20%2B%20dfs%28i%20-%202%29%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%EF%BC%9A%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20return%20dfs%28n%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs%28n%29%0A%20%20%20%20print%28f%22%E7%88%AC%20%7Bn%7D%20%E9%98%B6%E6%A5%BC%E6%A2%AF%E5%85%B1%E6%9C%89%20%7Bres%7D%20%E7%A7%8D%E6%96%B9%E6%A1%88%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following image shows the recursive tree formed by brute force search. For the problem <span class="arithmatex">\(dp[n]\)</span>, the depth of its recursive tree is <span class="arithmatex">\(n\)</span>, with a time complexity of <span class="arithmatex">\(O(2^n)\)</span>. Exponential order represents explosive growth, and entering a long wait if a relatively large <span class="arithmatex">\(n\)</span> is input.</p>
<p>Figure 14-3 shows the recursive tree formed by brute force search. For the problem <span class="arithmatex">\(dp[n]\)</span>, the depth of its recursive tree is <span class="arithmatex">\(n\)</span>, with a time complexity of <span class="arithmatex">\(O(2^n)\)</span>. Exponential order represents explosive growth, and entering a long wait if a relatively large <span class="arithmatex">\(n\)</span> is input.</p>
<p><a class="glightbox" href="../intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursive tree for climbing stairs" class="animation-figure" src="../intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png" /></a></p>
<p align="center"> Figure 14-3 &nbsp; Recursive tree for climbing stairs </p>
<p>Observing the above image, <strong>the exponential time complexity is caused by 'overlapping subproblems'</strong>. For example, <span class="arithmatex">\(dp[9]\)</span> is decomposed into <span class="arithmatex">\(dp[8]\)</span> and <span class="arithmatex">\(dp[7]\)</span>, <span class="arithmatex">\(dp[8]\)</span> into <span class="arithmatex">\(dp[7]\)</span> and <span class="arithmatex">\(dp[6]\)</span>, both containing the subproblem <span class="arithmatex">\(dp[7]\)</span>.</p>
<p>Observing Figure 14-3, <strong>the exponential time complexity is caused by 'overlapping subproblems'</strong>. For example, <span class="arithmatex">\(dp[9]\)</span> is decomposed into <span class="arithmatex">\(dp[8]\)</span> and <span class="arithmatex">\(dp[7]\)</span>, <span class="arithmatex">\(dp[8]\)</span> into <span class="arithmatex">\(dp[7]\)</span> and <span class="arithmatex">\(dp[6]\)</span>, both containing the subproblem <span class="arithmatex">\(dp[7]\)</span>.</p>
<p>Thus, subproblems include even smaller overlapping subproblems, endlessly. A vast majority of computational resources are wasted on these overlapping subproblems.</p>
<h2 id="1412-method-2-memoized-search">14.1.2 &nbsp; Method 2: Memoized search<a class="headerlink" href="#1412-method-2-memoized-search" title="Permanent link">&para;</a></h2>
<p>To enhance algorithm efficiency, <strong>we hope that all overlapping subproblems are calculated only once</strong>. For this purpose, we declare an array <code>mem</code> to record the solution of each subproblem, and prune overlapping subproblems during the search process.</p>
@ -4632,7 +4632,7 @@ dp[i] = dp[i-1] + dp[i-2]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20dfs%28i%3A%20int,%20mem%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%B2%E7%9F%A5%20dp%5B1%5D%20%E5%92%8C%20dp%5B2%5D%20%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B9%8B%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20%E8%8B%A5%E5%AD%98%E5%9C%A8%E8%AE%B0%E5%BD%95%20dp%5Bi%5D%20%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E4%B9%8B%0A%20%20%20%20if%20mem%5Bi%5D%20!%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201,%20mem%29%20%2B%20dfs%28i%20-%202,%20mem%29%0A%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%20dp%5Bi%5D%0A%20%20%20%20mem%5Bi%5D%20%3D%20count%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs_mem%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%EF%BC%9A%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20mem%5Bi%5D%20%E8%AE%B0%E5%BD%95%E7%88%AC%E5%88%B0%E7%AC%AC%20i%20%E9%98%B6%E7%9A%84%E6%96%B9%E6%A1%88%E6%80%BB%E6%95%B0%EF%BC%8C-1%20%E4%BB%A3%E8%A1%A8%E6%97%A0%E8%AE%B0%E5%BD%95%0A%20%20%20%20mem%20%3D%20%5B-1%5D%20*%20%28n%20%2B%201%29%0A%20%20%20%20return%20dfs%28n,%20mem%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs_mem%28n%29%0A%20%20%20%20print%28f%22%E7%88%AC%20%7Bn%7D%20%E9%98%B6%E6%A5%BC%E6%A2%AF%E5%85%B1%E6%9C%89%20%7Bres%7D%20%E7%A7%8D%E6%96%B9%E6%A1%88%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20dfs%28i%3A%20int,%20mem%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%B2%E7%9F%A5%20dp%5B1%5D%20%E5%92%8C%20dp%5B2%5D%20%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B9%8B%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20%E8%8B%A5%E5%AD%98%E5%9C%A8%E8%AE%B0%E5%BD%95%20dp%5Bi%5D%20%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E4%B9%8B%0A%20%20%20%20if%20mem%5Bi%5D%20!%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201,%20mem%29%20%2B%20dfs%28i%20-%202,%20mem%29%0A%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%20dp%5Bi%5D%0A%20%20%20%20mem%5Bi%5D%20%3D%20count%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs_mem%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%EF%BC%9A%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20mem%5Bi%5D%20%E8%AE%B0%E5%BD%95%E7%88%AC%E5%88%B0%E7%AC%AC%20i%20%E9%98%B6%E7%9A%84%E6%96%B9%E6%A1%88%E6%80%BB%E6%95%B0%EF%BC%8C-1%20%E4%BB%A3%E8%A1%A8%E6%97%A0%E8%AE%B0%E5%BD%95%0A%20%20%20%20mem%20%3D%20%5B-1%5D%20*%20%28n%20%2B%201%29%0A%20%20%20%20return%20dfs%28n,%20mem%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs_mem%28n%29%0A%20%20%20%20print%28f%22%E7%88%AC%20%7Bn%7D%20%E9%98%B6%E6%A5%BC%E6%A2%AF%E5%85%B1%E6%9C%89%20%7Bres%7D%20%E7%A7%8D%E6%96%B9%E6%A1%88%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>Observe the following image, <strong>after memoization, all overlapping subproblems need to be calculated only once, optimizing the time complexity to <span class="arithmatex">\(O(n)\)</span></strong>, which is a significant leap.</p>
<p>Observe Figure 14-4, <strong>after memoization, all overlapping subproblems need to be calculated only once, optimizing the time complexity to <span class="arithmatex">\(O(n)\)</span></strong>, which is a significant leap.</p>
<p><a class="glightbox" href="../intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursive tree with memoized search" class="animation-figure" src="../intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png" /></a></p>
<p align="center"> Figure 14-4 &nbsp; Recursive tree with memoized search </p>
@ -4888,7 +4888,7 @@ dp[i] = dp[i-1] + dp[i-2]
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20climbing_stairs_dp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%20%3D%20%5B0%5D%20*%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81%EF%BC%9A%E9%A2%84%E8%AE%BE%E6%9C%80%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%5B1%5D,%20dp%5B2%5D%20%3D%201,%202%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E4%BB%8E%E8%BE%83%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E9%80%90%E6%AD%A5%E6%B1%82%E8%A7%A3%E8%BE%83%E5%A4%A7%E5%AD%90%E9%97%AE%E9%A2%98%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20dp%5Bi%20-%201%5D%20%2B%20dp%5Bi%20-%202%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dp%28n%29%0A%20%20%20%20print%28f%22%E7%88%AC%20%7Bn%7D%20%E9%98%B6%E6%A5%BC%E6%A2%AF%E5%85%B1%E6%9C%89%20%7Bres%7D%20%E7%A7%8D%E6%96%B9%E6%A1%88%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20climbing_stairs_dp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%88%AC%E6%A5%BC%E6%A2%AF%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%20%3D%20%5B0%5D%20*%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81%EF%BC%9A%E9%A2%84%E8%AE%BE%E6%9C%80%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%0A%20%20%20%20dp%5B1%5D,%20dp%5B2%5D%20%3D%201,%202%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E4%BB%8E%E8%BE%83%E5%B0%8F%E5%AD%90%E9%97%AE%E9%A2%98%E9%80%90%E6%AD%A5%E6%B1%82%E8%A7%A3%E8%BE%83%E5%A4%A7%E5%AD%90%E9%97%AE%E9%A2%98%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20dp%5Bi%20-%201%5D%20%2B%20dp%5Bi%20-%202%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dp%28n%29%0A%20%20%20%20print%28f%22%E7%88%AC%20%7Bn%7D%20%E9%98%B6%E6%A5%BC%E6%A2%AF%E5%85%B1%E6%9C%89%20%7Bres%7D%20%E7%A7%8D%E6%96%B9%E6%A1%88%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The image below simulates the execution process of the above code.</p>
<p>Figure 14-5 simulates the execution process of the above code.</p>
<p><a class="glightbox" href="../intro_to_dynamic_programming.assets/climbing_stairs_dp.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Dynamic programming process for climbing stairs" class="animation-figure" src="../intro_to_dynamic_programming.assets/climbing_stairs_dp.png" /></a></p>
<p align="center"> Figure 14-5 &nbsp; Dynamic programming process for climbing stairs </p>

View File

@ -3633,7 +3633,7 @@
<p class="admonition-title">Question</p>
<p>Given <span class="arithmatex">\(n\)</span> items, the weight of the <span class="arithmatex">\(i\)</span>-th item is <span class="arithmatex">\(wgt[i-1]\)</span> and its value is <span class="arithmatex">\(val[i-1]\)</span>, and a knapsack with a capacity of <span class="arithmatex">\(cap\)</span>. Each item can be chosen only once. What is the maximum value of items that can be placed in the knapsack under the capacity limit?</p>
</div>
<p>Observe the following figure, since the item number <span class="arithmatex">\(i\)</span> starts counting from 1, and the array index starts from 0, thus the weight of item <span class="arithmatex">\(i\)</span> corresponds to <span class="arithmatex">\(wgt[i-1]\)</span> and the value corresponds to <span class="arithmatex">\(val[i-1]\)</span>.</p>
<p>Observe Figure 14-17, since the item number <span class="arithmatex">\(i\)</span> starts counting from 1, and the array index starts from 0, thus the weight of item <span class="arithmatex">\(i\)</span> corresponds to <span class="arithmatex">\(wgt[i-1]\)</span> and the value corresponds to <span class="arithmatex">\(val[i-1]\)</span>.</p>
<p><a class="glightbox" href="../knapsack_problem.assets/knapsack_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example data of the 0-1 knapsack" class="animation-figure" src="../knapsack_problem.assets/knapsack_example.png" /></a></p>
<p align="center"> Figure 14-17 &nbsp; Example data of the 0-1 knapsack </p>
@ -3933,7 +3933,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20knapsack_dfs%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20i%3A%20int,%20c%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E8%83%8C%E5%8C%85%EF%BC%9A%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E9%80%89%E5%AE%8C%E6%89%80%E6%9C%89%E7%89%A9%E5%93%81%E6%88%96%E8%83%8C%E5%8C%85%E6%97%A0%E5%89%A9%E4%BD%99%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E4%BB%B7%E5%80%BC%200%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E8%8B%A5%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E5%8F%AA%E8%83%BD%E9%80%89%E6%8B%A9%E4%B8%8D%E6%94%BE%E5%85%A5%E8%83%8C%E5%8C%85%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%29%0A%20%20%20%20%23%20%E8%AE%A1%E7%AE%97%E4%B8%8D%E6%94%BE%E5%85%A5%E5%92%8C%E6%94%BE%E5%85%A5%E7%89%A9%E5%93%81%20i%20%E7%9A%84%E6%9C%80%E5%A4%A7%E4%BB%B7%E5%80%BC%0A%20%20%20%20no%20%3D%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E8%BF%94%E5%9B%9E%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88%E4%B8%AD%E4%BB%B7%E5%80%BC%E6%9B%B4%E5%A4%A7%E7%9A%84%E9%82%A3%E4%B8%80%E4%B8%AA%0A%20%20%20%20return%20max%28no,%20yes%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%0A%20%20%20%20res%20%3D%20knapsack_dfs%28wgt,%20val,%20n,%20cap%29%0A%20%20%20%20print%28f%22%E4%B8%8D%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%E7%9A%84%E6%9C%80%E5%A4%A7%E7%89%A9%E5%93%81%E4%BB%B7%E5%80%BC%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=7&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20knapsack_dfs%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20i%3A%20int,%20c%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E8%83%8C%E5%8C%85%EF%BC%9A%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E9%80%89%E5%AE%8C%E6%89%80%E6%9C%89%E7%89%A9%E5%93%81%E6%88%96%E8%83%8C%E5%8C%85%E6%97%A0%E5%89%A9%E4%BD%99%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E4%BB%B7%E5%80%BC%200%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E8%8B%A5%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E5%8F%AA%E8%83%BD%E9%80%89%E6%8B%A9%E4%B8%8D%E6%94%BE%E5%85%A5%E8%83%8C%E5%8C%85%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%29%0A%20%20%20%20%23%20%E8%AE%A1%E7%AE%97%E4%B8%8D%E6%94%BE%E5%85%A5%E5%92%8C%E6%94%BE%E5%85%A5%E7%89%A9%E5%93%81%20i%20%E7%9A%84%E6%9C%80%E5%A4%A7%E4%BB%B7%E5%80%BC%0A%20%20%20%20no%20%3D%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E8%BF%94%E5%9B%9E%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88%E4%B8%AD%E4%BB%B7%E5%80%BC%E6%9B%B4%E5%A4%A7%E7%9A%84%E9%82%A3%E4%B8%80%E4%B8%AA%0A%20%20%20%20return%20max%28no,%20yes%29%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E6%9A%B4%E5%8A%9B%E6%90%9C%E7%B4%A2%0A%20%20%20%20res%20%3D%20knapsack_dfs%28wgt,%20val,%20n,%20cap%29%0A%20%20%20%20print%28f%22%E4%B8%8D%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%E7%9A%84%E6%9C%80%E5%A4%A7%E7%89%A9%E5%93%81%E4%BB%B7%E5%80%BC%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=7&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown in the Figure 14-18 , since each item generates two search branches of not selecting and selecting, the time complexity is <span class="arithmatex">\(O(2^n)\)</span>.</p>
<p>As shown in Figure 14-18, since each item generates two search branches of not selecting and selecting, the time complexity is <span class="arithmatex">\(O(2^n)\)</span>.</p>
<p>Observing the recursive tree, it is easy to see that there are overlapping sub-problems, such as <span class="arithmatex">\(dp[1, 10]\)</span>, etc. When there are many items and the knapsack capacity is large, especially when there are many items of the same weight, the number of overlapping sub-problems will increase significantly.</p>
<p><a class="glightbox" href="../knapsack_problem.assets/knapsack_dfs.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="The brute force search recursive tree of the 0-1 knapsack problem" class="animation-figure" src="../knapsack_problem.assets/knapsack_dfs.png" /></a></p>
<p align="center"> Figure 14-18 &nbsp; The brute force search recursive tree of the 0-1 knapsack problem </p>
@ -4284,12 +4284,12 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20knapsack_dfs_mem%28%0A%20%20%20%20wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20mem%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20c%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E8%83%8C%E5%8C%85%EF%BC%9A%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E9%80%89%E5%AE%8C%E6%89%80%E6%9C%89%E7%89%A9%E5%93%81%E6%88%96%E8%83%8C%E5%8C%85%E6%97%A0%E5%89%A9%E4%BD%99%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E4%BB%B7%E5%80%BC%200%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E6%9C%89%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%0A%20%20%20%20if%20mem%5Bi%5D%5Bc%5D%20!%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%20%20%20%20%23%20%E8%8B%A5%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E5%8F%AA%E8%83%BD%E9%80%89%E6%8B%A9%E4%B8%8D%E6%94%BE%E5%85%A5%E8%83%8C%E5%8C%85%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%29%0A%20%20%20%20%23%20%E8%AE%A1%E7%AE%97%E4%B8%8D%E6%94%BE%E5%85%A5%E5%92%8C%E6%94%BE%E5%85%A5%E7%89%A9%E5%93%81%20i%20%E7%9A%84%E6%9C%80%E5%A4%A7%E4%BB%B7%E5%80%BC%0A%20%20%20%20no%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%E5%B9%B6%E8%BF%94%E5%9B%9E%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88%E4%B8%AD%E4%BB%B7%E5%80%BC%E6%9B%B4%E5%A4%A7%E7%9A%84%E9%82%A3%E4%B8%80%E4%B8%AA%0A%20%20%20%20mem%5Bi%5D%5Bc%5D%20%3D%20max%28no,%20yes%29%0A%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20*%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20res%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20n,%20cap%29%0A%20%20%20%20print%28f%22%E4%B8%8D%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%E7%9A%84%E6%9C%80%E5%A4%A7%E7%89%A9%E5%93%81%E4%BB%B7%E5%80%BC%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=20&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20knapsack_dfs_mem%28%0A%20%20%20%20wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20mem%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20c%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E8%83%8C%E5%8C%85%EF%BC%9A%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E9%80%89%E5%AE%8C%E6%89%80%E6%9C%89%E7%89%A9%E5%93%81%E6%88%96%E8%83%8C%E5%8C%85%E6%97%A0%E5%89%A9%E4%BD%99%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E4%BB%B7%E5%80%BC%200%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E8%8B%A5%E5%B7%B2%E6%9C%89%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%0A%20%20%20%20if%20mem%5Bi%5D%5Bc%5D%20!%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%20%20%20%20%23%20%E8%8B%A5%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%EF%BC%8C%E5%88%99%E5%8F%AA%E8%83%BD%E9%80%89%E6%8B%A9%E4%B8%8D%E6%94%BE%E5%85%A5%E8%83%8C%E5%8C%85%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%29%0A%20%20%20%20%23%20%E8%AE%A1%E7%AE%97%E4%B8%8D%E6%94%BE%E5%85%A5%E5%92%8C%E6%94%BE%E5%85%A5%E7%89%A9%E5%93%81%20i%20%E7%9A%84%E6%9C%80%E5%A4%A7%E4%BB%B7%E5%80%BC%0A%20%20%20%20no%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E8%AE%B0%E5%BD%95%E5%B9%B6%E8%BF%94%E5%9B%9E%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88%E4%B8%AD%E4%BB%B7%E5%80%BC%E6%9B%B4%E5%A4%A7%E7%9A%84%E9%82%A3%E4%B8%80%E4%B8%AA%0A%20%20%20%20mem%5Bi%5D%5Bc%5D%20%3D%20max%28no,%20yes%29%0A%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E8%AE%B0%E5%BF%86%E5%8C%96%E6%90%9C%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20*%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20res%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20n,%20cap%29%0A%20%20%20%20print%28f%22%E4%B8%8D%E8%B6%85%E8%BF%87%E8%83%8C%E5%8C%85%E5%AE%B9%E9%87%8F%E7%9A%84%E6%9C%80%E5%A4%A7%E7%89%A9%E5%93%81%E4%BB%B7%E5%80%BC%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=20&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following figure shows the search branches that are pruned in memoized search.</p>
<p>Figure 14-19 shows the search branches that are pruned in memoized search.</p>
<p><a class="glightbox" href="../knapsack_problem.assets/knapsack_dfs_mem.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="The memoized search recursive tree of the 0-1 knapsack problem" class="animation-figure" src="../knapsack_problem.assets/knapsack_dfs_mem.png" /></a></p>
<p align="center"> Figure 14-19 &nbsp; The memoized search recursive tree of the 0-1 knapsack problem </p>
<h3 id="3-method-three-dynamic-programming">3. &nbsp; Method three: Dynamic programming<a class="headerlink" href="#3-method-three-dynamic-programming" title="Permanent link">&para;</a></h3>
<p>Dynamic programming essentially involves filling the <span class="arithmatex">\(dp\)</span> table during the state transition, the code is shown below:</p>
<p>Dynamic programming essentially involves filling the <span class="arithmatex">\(dp\)</span> table during the state transition, the code is shown in Figure 14-20:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="3:14"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><input id="__tabbed_3_3" name="__tabbed_3" type="radio" /><input id="__tabbed_3_4" name="__tabbed_3" type="radio" /><input id="__tabbed_3_5" name="__tabbed_3" type="radio" /><input id="__tabbed_3_6" name="__tabbed_3" type="radio" /><input id="__tabbed_3_7" name="__tabbed_3" type="radio" /><input id="__tabbed_3_8" name="__tabbed_3" type="radio" /><input id="__tabbed_3_9" name="__tabbed_3" type="radio" /><input id="__tabbed_3_10" name="__tabbed_3" type="radio" /><input id="__tabbed_3_11" name="__tabbed_3" type="radio" /><input id="__tabbed_3_12" name="__tabbed_3" type="radio" /><input id="__tabbed_3_13" name="__tabbed_3" type="radio" /><input id="__tabbed_3_14" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">Python</label><label for="__tabbed_3_2">C++</label><label for="__tabbed_3_3">Java</label><label for="__tabbed_3_4">C#</label><label for="__tabbed_3_5">Go</label><label for="__tabbed_3_6">Swift</label><label for="__tabbed_3_7">JS</label><label for="__tabbed_3_8">TS</label><label for="__tabbed_3_9">Dart</label><label for="__tabbed_3_10">Rust</label><label for="__tabbed_3_11">C</label><label for="__tabbed_3_12">Kotlin</label><label for="__tabbed_3_13">Ruby</label><label for="__tabbed_3_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -4155,7 +4155,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1])
</details>
<h3 id="3-space-optimization">3. &nbsp; Space optimization<a class="headerlink" href="#3-space-optimization" title="Permanent link">&para;</a></h3>
<p>Since the current state comes from the state to the left and above, <strong>the space-optimized solution should perform a forward traversal for each row in the <span class="arithmatex">\(dp\)</span> table</strong>.</p>
<p>This traversal order is the opposite of that for the 0-1 knapsack. Please refer to the following figures to understand the difference.</p>
<p>This traversal order is the opposite of that for the 0-1 knapsack. Please refer to Figure 14-23 to understand the difference.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:6"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">&lt;1&gt;</label><label for="__tabbed_2_2">&lt;2&gt;</label><label for="__tabbed_2_3">&lt;3&gt;</label><label for="__tabbed_2_4">&lt;4&gt;</label><label for="__tabbed_2_5">&lt;5&gt;</label><label for="__tabbed_2_6">&lt;6&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -4908,7 +4908,7 @@ dp[i, a] = \min(dp[i-1, a], dp[i, a - coins[i-1]] + 1)
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20coin_change_dp%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20MAX%20%3D%20amt%20%2B%201%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20*%20%28amt%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E8%A1%8C%E9%A6%96%E5%88%97%0A%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Ba%5D%20%3D%20MAX%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E5%85%B6%E4%BD%99%E8%A1%8C%E5%92%8C%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8B%A5%E8%B6%85%E8%BF%87%E7%9B%AE%E6%A0%87%E9%87%91%E9%A2%9D%EF%BC%8C%E5%88%99%E4%B8%8D%E9%80%89%E7%A1%AC%E5%B8%81%20i%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E4%B8%8D%E9%80%89%E5%92%8C%E9%80%89%E7%A1%AC%E5%B8%81%20i%20%E8%BF%99%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88%E7%9A%84%E8%BE%83%E5%B0%8F%E5%80%BC%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20min%28dp%5Bi%20-%201%5D%5Ba%5D,%20dp%5Bi%5D%5Ba%20-%20coins%5Bi%20-%201%5D%5D%20%2B%201%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bamt%5D%20if%20dp%5Bn%5D%5Bamt%5D%20!%3D%20MAX%20else%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1,%202,%205%5D%0A%20%20%20%20amt%20%3D%204%0A%0A%20%20%20%20%23%20%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%0A%20%20%20%20res%20%3D%20coin_change_dp%28coins,%20amt%29%0A%20%20%20%20print%28f%22%E5%87%91%E5%88%B0%E7%9B%AE%E6%A0%87%E9%87%91%E9%A2%9D%E6%89%80%E9%9C%80%E7%9A%84%E6%9C%80%E5%B0%91%E7%A1%AC%E5%B8%81%E6%95%B0%E9%87%8F%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20coin_change_dp%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2%EF%BC%9A%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20MAX%20%3D%20amt%20%2B%201%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20dp%20%E8%A1%A8%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20*%20%28amt%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E9%A6%96%E8%A1%8C%E9%A6%96%E5%88%97%0A%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Ba%5D%20%3D%20MAX%0A%20%20%20%20%23%20%E7%8A%B6%E6%80%81%E8%BD%AC%E7%A7%BB%EF%BC%9A%E5%85%B6%E4%BD%99%E8%A1%8C%E5%92%8C%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8B%A5%E8%B6%85%E8%BF%87%E7%9B%AE%E6%A0%87%E9%87%91%E9%A2%9D%EF%BC%8C%E5%88%99%E4%B8%8D%E9%80%89%E7%A1%AC%E5%B8%81%20i%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E4%B8%8D%E9%80%89%E5%92%8C%E9%80%89%E7%A1%AC%E5%B8%81%20i%20%E8%BF%99%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%A1%88%E7%9A%84%E8%BE%83%E5%B0%8F%E5%80%BC%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20min%28dp%5Bi%20-%201%5D%5Ba%5D,%20dp%5Bi%5D%5Ba%20-%20coins%5Bi%20-%201%5D%5D%20%2B%201%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bamt%5D%20if%20dp%5Bn%5D%5Bamt%5D%20!%3D%20MAX%20else%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1,%202,%205%5D%0A%20%20%20%20amt%20%3D%204%0A%0A%20%20%20%20%23%20%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%0A%20%20%20%20res%20%3D%20coin_change_dp%28coins,%20amt%29%0A%20%20%20%20print%28f%22%E5%87%91%E5%88%B0%E7%9B%AE%E6%A0%87%E9%87%91%E9%A2%9D%E6%89%80%E9%9C%80%E7%9A%84%E6%9C%80%E5%B0%91%E7%A1%AC%E5%B8%81%E6%95%B0%E9%87%8F%E4%B8%BA%20%7Bres%7D%22%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>The following images show the dynamic programming process for the coin change problem, which is very similar to the unbounded knapsack problem.</p>
<p>Figure 14-25 show the dynamic programming process for the coin change problem, which is very similar to the unbounded knapsack problem.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="5:15"><input checked="checked" id="__tabbed_5_1" name="__tabbed_5" type="radio" /><input id="__tabbed_5_2" name="__tabbed_5" type="radio" /><input id="__tabbed_5_3" name="__tabbed_5" type="radio" /><input id="__tabbed_5_4" name="__tabbed_5" type="radio" /><input id="__tabbed_5_5" name="__tabbed_5" type="radio" /><input id="__tabbed_5_6" name="__tabbed_5" type="radio" /><input id="__tabbed_5_7" name="__tabbed_5" type="radio" /><input id="__tabbed_5_8" name="__tabbed_5" type="radio" /><input id="__tabbed_5_9" name="__tabbed_5" type="radio" /><input id="__tabbed_5_10" name="__tabbed_5" type="radio" /><input id="__tabbed_5_11" name="__tabbed_5" type="radio" /><input id="__tabbed_5_12" name="__tabbed_5" type="radio" /><input id="__tabbed_5_13" name="__tabbed_5" type="radio" /><input id="__tabbed_5_14" name="__tabbed_5" type="radio" /><input id="__tabbed_5_15" name="__tabbed_5" type="radio" /><div class="tabbed-labels"><label for="__tabbed_5_1">&lt;1&gt;</label><label for="__tabbed_5_2">&lt;2&gt;</label><label for="__tabbed_5_3">&lt;3&gt;</label><label for="__tabbed_5_4">&lt;4&gt;</label><label for="__tabbed_5_5">&lt;5&gt;</label><label for="__tabbed_5_6">&lt;6&gt;</label><label for="__tabbed_5_7">&lt;7&gt;</label><label for="__tabbed_5_8">&lt;8&gt;</label><label for="__tabbed_5_9">&lt;9&gt;</label><label for="__tabbed_5_10">&lt;10&gt;</label><label for="__tabbed_5_11">&lt;11&gt;</label><label for="__tabbed_5_12">&lt;12&gt;</label><label for="__tabbed_5_13">&lt;13&gt;</label><label for="__tabbed_5_14">&lt;14&gt;</label><label for="__tabbed_5_15">&lt;15&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -3665,12 +3665,12 @@ E &amp; = \{ (1,2), (1,3), (1,5), (2,3), (2,4), (2,5), (4,5) \} \newline
G &amp; = \{ V, E \} \newline
\end{aligned}
\]</div>
<p>If vertices are viewed as nodes and edges as references (pointers) connecting the nodes, graphs can be seen as a data structure that extends from linked lists. As shown below, <strong>compared to linear relationships (linked lists) and divide-and-conquer relationships (trees), network relationships (graphs) are more complex due to their higher degree of freedom</strong>.</p>
<p>If vertices are viewed as nodes and edges as references (pointers) connecting the nodes, graphs can be seen as a data structure that extends from linked lists. As shown in Figure 9-1, <strong>compared to linear relationships (linked lists) and divide-and-conquer relationships (trees), network relationships (graphs) are more complex due to their higher degree of freedom</strong>.</p>
<p><a class="glightbox" href="../graph.assets/linkedlist_tree_graph.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Relationship between linked lists, trees, and graphs" class="animation-figure" src="../graph.assets/linkedlist_tree_graph.png" /></a></p>
<p align="center"> Figure 9-1 &nbsp; Relationship between linked lists, trees, and graphs </p>
<h2 id="911-common-types-of-graphs">9.1.1 &nbsp; Common types of graphs<a class="headerlink" href="#911-common-types-of-graphs" title="Permanent link">&para;</a></h2>
<p>Based on whether edges have direction, graphs can be divided into "undirected graphs" and "directed graphs", as shown below.</p>
<p>Based on whether edges have direction, graphs can be divided into "undirected graphs" and "directed graphs", as shown in Figure 9-2.</p>
<ul>
<li>In undirected graphs, edges represent a "bidirectional" connection between two vertices, for example, the "friendship" in WeChat or QQ.</li>
<li>In directed graphs, edges have directionality, that is, the edges <span class="arithmatex">\(A \rightarrow B\)</span> and <span class="arithmatex">\(A \leftarrow B\)</span> are independent of each other, for example, the "follow" and "be followed" relationship on Weibo or TikTok.</li>
@ -3678,7 +3678,7 @@ G &amp; = \{ V, E \} \newline
<p><a class="glightbox" href="../graph.assets/directed_graph.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Directed and undirected graphs" class="animation-figure" src="../graph.assets/directed_graph.png" /></a></p>
<p align="center"> Figure 9-2 &nbsp; Directed and undirected graphs </p>
<p>Based on whether all vertices are connected, graphs can be divided into "connected graphs" and "disconnected graphs", as shown below.</p>
<p>Based on whether all vertices are connected, graphs can be divided into "connected graphs" and "disconnected graphs", as shown in Figure 9-3.</p>
<ul>
<li>For connected graphs, it is possible to reach any other vertex starting from a certain vertex.</li>
<li>For disconnected graphs, there is at least one vertex that cannot be reached from a certain starting vertex.</li>
@ -3686,21 +3686,21 @@ G &amp; = \{ V, E \} \newline
<p><a class="glightbox" href="../graph.assets/connected_graph.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Connected and disconnected graphs" class="animation-figure" src="../graph.assets/connected_graph.png" /></a></p>
<p align="center"> Figure 9-3 &nbsp; Connected and disconnected graphs </p>
<p>We can also add a "weight" variable to edges, resulting in "weighted graphs" as shown below. For example, in mobile games like "Honor of Kings", the system calculates the "closeness" between players based on shared gaming time, and this closeness network can be represented with a weighted graph.</p>
<p>We can also add a "weight" variable to edges, resulting in "weighted graphs" as shown in Figure 9-4. For example, in mobile games like "Honor of Kings", the system calculates the "closeness" between players based on shared gaming time, and this closeness network can be represented with a weighted graph.</p>
<p><a class="glightbox" href="../graph.assets/weighted_graph.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Weighted and unweighted graphs" class="animation-figure" src="../graph.assets/weighted_graph.png" /></a></p>
<p align="center"> Figure 9-4 &nbsp; Weighted and unweighted graphs </p>
<p>Graph data structures include the following commonly used terms.</p>
<ul>
<li>"Adjacency": When there is an edge connecting two vertices, these two vertices are said to be "adjacent". In the above figure, the adjacent vertices of vertex 1 are vertices 2, 3, and 5.</li>
<li>"Path": The sequence of edges passed from vertex A to vertex B is called a "path" from A to B. In the above figure, the edge sequence 1-5-2-4 is a path from vertex 1 to vertex 4.</li>
<li>"Adjacency": When there is an edge connecting two vertices, these two vertices are said to be "adjacent". In Figure 9-4, the adjacent vertices of vertex 1 are vertices 2, 3, and 5.</li>
<li>"Path": The sequence of edges passed from vertex A to vertex B is called a "path" from A to B. In Figure 9-4, the edge sequence 1-5-2-4 is a path from vertex 1 to vertex 4.</li>
<li>"Degree": The number of edges a vertex has. For directed graphs, "in-degree" refers to how many edges point to the vertex, and "out-degree" refers to how many edges point out from the vertex.</li>
</ul>
<h2 id="912-representation-of-graphs">9.1.2 &nbsp; Representation of graphs<a class="headerlink" href="#912-representation-of-graphs" title="Permanent link">&para;</a></h2>
<p>Common representations of graphs include "adjacency matrices" and "adjacency lists". The following examples use undirected graphs.</p>
<h3 id="1-adjacency-matrix">1. &nbsp; Adjacency matrix<a class="headerlink" href="#1-adjacency-matrix" title="Permanent link">&para;</a></h3>
<p>Let the number of vertices in the graph be <span class="arithmatex">\(n\)</span>, the "adjacency matrix" uses an <span class="arithmatex">\(n \times n\)</span> matrix to represent the graph, where each row (column) represents a vertex, and the matrix elements represent edges, with <span class="arithmatex">\(1\)</span> or <span class="arithmatex">\(0\)</span> indicating whether there is an edge between two vertices.</p>
<p>As shown below, let the adjacency matrix be <span class="arithmatex">\(M\)</span>, and the list of vertices be <span class="arithmatex">\(V\)</span>, then the matrix element <span class="arithmatex">\(M[i, j] = 1\)</span> indicates there is an edge between vertex <span class="arithmatex">\(V[i]\)</span> and vertex <span class="arithmatex">\(V[j]\)</span>, conversely <span class="arithmatex">\(M[i, j] = 0\)</span> indicates there is no edge between the two vertices.</p>
<p>As shown in Figure 9-5, let the adjacency matrix be <span class="arithmatex">\(M\)</span>, and the list of vertices be <span class="arithmatex">\(V\)</span>, then the matrix element <span class="arithmatex">\(M[i, j] = 1\)</span> indicates there is an edge between vertex <span class="arithmatex">\(V[i]\)</span> and vertex <span class="arithmatex">\(V[j]\)</span>, conversely <span class="arithmatex">\(M[i, j] = 0\)</span> indicates there is no edge between the two vertices.</p>
<p><a class="glightbox" href="../graph.assets/adjacency_matrix.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Representation of a graph with an adjacency matrix" class="animation-figure" src="../graph.assets/adjacency_matrix.png" /></a></p>
<p align="center"> Figure 9-5 &nbsp; Representation of a graph with an adjacency matrix </p>
@ -3712,14 +3712,14 @@ G &amp; = \{ V, E \} \newline
</ul>
<p>When representing graphs with adjacency matrices, it is possible to directly access matrix elements to obtain edges, thus operations of addition, deletion, lookup, and modification are very efficient, all with a time complexity of <span class="arithmatex">\(O(1)\)</span>. However, the space complexity of the matrix is <span class="arithmatex">\(O(n^2)\)</span>, which consumes more memory.</p>
<h3 id="2-adjacency-list">2. &nbsp; Adjacency list<a class="headerlink" href="#2-adjacency-list" title="Permanent link">&para;</a></h3>
<p>The "adjacency list" uses <span class="arithmatex">\(n\)</span> linked lists to represent the graph, with each linked list node representing a vertex. The <span class="arithmatex">\(i\)</span>-th linked list corresponds to vertex <span class="arithmatex">\(i\)</span> and contains all adjacent vertices (vertices connected to that vertex). The Figure 9-6 shows an example of a graph stored using an adjacency list.</p>
<p>The "adjacency list" uses <span class="arithmatex">\(n\)</span> linked lists to represent the graph, with each linked list node representing a vertex. The <span class="arithmatex">\(i\)</span>-th linked list corresponds to vertex <span class="arithmatex">\(i\)</span> and contains all adjacent vertices (vertices connected to that vertex). Figure 9-6 shows an example of a graph stored using an adjacency list.</p>
<p><a class="glightbox" href="../graph.assets/adjacency_list.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Representation of a graph with an adjacency list" class="animation-figure" src="../graph.assets/adjacency_list.png" /></a></p>
<p align="center"> Figure 9-6 &nbsp; Representation of a graph with an adjacency list </p>
<p>The adjacency list only stores actual edges, and the total number of edges is often much less than <span class="arithmatex">\(n^2\)</span>, making it more space-efficient. However, finding edges in the adjacency list requires traversing the linked list, so its time efficiency is not as good as that of the adjacency matrix.</p>
<p>Observing the above figure, <strong>the structure of the adjacency list is very similar to the "chaining" in hash tables, hence we can use similar methods to optimize efficiency</strong>. For example, when the linked list is long, it can be transformed into an AVL tree or red-black tree, thus optimizing the time efficiency from <span class="arithmatex">\(O(n)\)</span> to <span class="arithmatex">\(O(\log n)\)</span>; the linked list can also be transformed into a hash table, thus reducing the time complexity to <span class="arithmatex">\(O(1)\)</span>.</p>
<p>Observing Figure 9-6, <strong>the structure of the adjacency list is very similar to the "chaining" in hash tables, hence we can use similar methods to optimize efficiency</strong>. For example, when the linked list is long, it can be transformed into an AVL tree or red-black tree, thus optimizing the time efficiency from <span class="arithmatex">\(O(n)\)</span> to <span class="arithmatex">\(O(\log n)\)</span>; the linked list can also be transformed into a hash table, thus reducing the time complexity to <span class="arithmatex">\(O(1)\)</span>.</p>
<h2 id="913-common-applications-of-graphs">9.1.3 &nbsp; Common applications of graphs<a class="headerlink" href="#913-common-applications-of-graphs" title="Permanent link">&para;</a></h2>
<p>As shown in the Table 9-1 , many real-world systems can be modeled with graphs, and corresponding problems can be reduced to graph computing problems.</p>
<p>As shown in Table 9-1, many real-world systems can be modeled with graphs, and corresponding problems can be reduced to graph computing problems.</p>
<p align="center"> Table 9-1 &nbsp; Common graphs in real life </p>
<div class="center-table">

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3611,13 +3611,13 @@
<h1 id="152-fractional-knapsack-problem">15.2 &nbsp; Fractional knapsack problem<a class="headerlink" href="#152-fractional-knapsack-problem" title="Permanent link">&para;</a></h1>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>Given <span class="arithmatex">\(n\)</span> items, the weight of the <span class="arithmatex">\(i\)</span>-th item is <span class="arithmatex">\(wgt[i-1]\)</span> and its value is <span class="arithmatex">\(val[i-1]\)</span>, and a knapsack with a capacity of <span class="arithmatex">\(cap\)</span>. Each item can be chosen only once, <strong>but a part of the item can be selected, with its value calculated based on the proportion of the weight chosen</strong>, what is the maximum value of the items in the knapsack under the limited capacity? An example is shown below.</p>
<p>Given <span class="arithmatex">\(n\)</span> items, the weight of the <span class="arithmatex">\(i\)</span>-th item is <span class="arithmatex">\(wgt[i-1]\)</span> and its value is <span class="arithmatex">\(val[i-1]\)</span>, and a knapsack with a capacity of <span class="arithmatex">\(cap\)</span>. Each item can be chosen only once, <strong>but a part of the item can be selected, with its value calculated based on the proportion of the weight chosen</strong>, what is the maximum value of the items in the knapsack under the limited capacity? An example is shown in Figure 15-3.</p>
</div>
<p><a class="glightbox" href="../fractional_knapsack_problem.assets/fractional_knapsack_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example data of the fractional knapsack problem" class="animation-figure" src="../fractional_knapsack_problem.assets/fractional_knapsack_example.png" /></a></p>
<p align="center"> Figure 15-3 &nbsp; Example data of the fractional knapsack problem </p>
<p>The fractional knapsack problem is very similar overall to the 0-1 knapsack problem, involving the current item <span class="arithmatex">\(i\)</span> and capacity <span class="arithmatex">\(c\)</span>, aiming to maximize the value within the limited capacity of the knapsack.</p>
<p>The difference is that, in this problem, only a part of an item can be chosen. As shown in the Figure 15-4 , <strong>we can arbitrarily split the items and calculate the corresponding value based on the weight proportion</strong>.</p>
<p>The difference is that, in this problem, only a part of an item can be chosen. As shown in Figure 15-4, <strong>we can arbitrarily split the items and calculate the corresponding value based on the weight proportion</strong>.</p>
<ol>
<li>For item <span class="arithmatex">\(i\)</span>, its value per unit weight is <span class="arithmatex">\(val[i-1] / wgt[i-1]\)</span>, referred to as the unit value.</li>
<li>Suppose we put a part of item <span class="arithmatex">\(i\)</span> with weight <span class="arithmatex">\(w\)</span> into the knapsack, then the value added to the knapsack is <span class="arithmatex">\(w \times val[i-1] / wgt[i-1]\)</span>.</li>
@ -3626,7 +3626,7 @@
<p align="center"> Figure 15-4 &nbsp; Value per unit weight of the item </p>
<h3 id="1-greedy-strategy-determination">1. &nbsp; Greedy strategy determination<a class="headerlink" href="#1-greedy-strategy-determination" title="Permanent link">&para;</a></h3>
<p>Maximizing the total value of the items in the knapsack essentially means maximizing the value per unit weight. From this, the greedy strategy shown below can be deduced.</p>
<p>Maximizing the total value of the items in the knapsack essentially means maximizing the value per unit weight. From this, the greedy strategy shown in Figure 15-5 can be deduced.</p>
<ol>
<li>Sort the items by their unit value from high to low.</li>
<li>Iterate over all items, <strong>greedily choosing the item with the highest unit value in each round</strong>.</li>
@ -4094,7 +4094,7 @@
<p>Using proof by contradiction. Suppose item <span class="arithmatex">\(x\)</span> has the highest unit value, and some algorithm yields a maximum value <code>res</code>, but the solution does not include item <span class="arithmatex">\(x\)</span>.</p>
<p>Now remove a unit weight of any item from the knapsack and replace it with a unit weight of item <span class="arithmatex">\(x\)</span>. Since the unit value of item <span class="arithmatex">\(x\)</span> is the highest, the total value after replacement will definitely be greater than <code>res</code>. <strong>This contradicts the assumption that <code>res</code> is the optimal solution, proving that the optimal solution must include item <span class="arithmatex">\(x\)</span></strong>.</p>
<p>For other items in this solution, we can also construct the above contradiction. Overall, <strong>items with greater unit value are always better choices</strong>, proving that the greedy strategy is effective.</p>
<p>As shown in the Figure 15-6 , if the item weight and unit value are viewed as the horizontal and vertical axes of a two-dimensional chart respectively, the fractional knapsack problem can be transformed into "seeking the largest area enclosed within a limited horizontal axis range". This analogy can help us understand the effectiveness of the greedy strategy from a geometric perspective.</p>
<p>As shown in Figure 15-6, if the item weight and unit value are viewed as the horizontal and vertical axes of a two-dimensional chart respectively, the fractional knapsack problem can be transformed into "seeking the largest area enclosed within a limited horizontal axis range". This analogy can help us understand the effectiveness of the greedy strategy from a geometric perspective.</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="Geometric representation of the fractional knapsack problem" class="animation-figure" src="../fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png" /></a></p>
<p align="center"> Figure 15-6 &nbsp; Geometric representation of the fractional knapsack problem </p>

View File

@ -3638,7 +3638,7 @@
<p class="admonition-title">Question</p>
<p>Given <span class="arithmatex">\(n\)</span> types of coins, where the denomination of the <span class="arithmatex">\(i\)</span>th type of coin is <span class="arithmatex">\(coins[i - 1]\)</span>, and the target amount is <span class="arithmatex">\(amt\)</span>, with each type of coin available indefinitely, what is the minimum number of coins needed to make up the target amount? If it is not possible to make up the target amount, return <span class="arithmatex">\(-1\)</span>.</p>
</div>
<p>The greedy strategy adopted in this problem is shown in the following figure. Given the target amount, <strong>we greedily choose the coin that is closest to and not greater than it</strong>, repeatedly following this step until the target amount is met.</p>
<p>The greedy strategy adopted in this problem is shown in Figure 15-1. Given the target amount, <strong>we greedily choose the coin that is closest to and not greater than it</strong>, repeatedly following this step until the target amount is met.</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="Greedy strategy for coin change" class="animation-figure" src="../greedy_algorithm.assets/coin_change_greedy_strategy.png" /></a></p>
<p align="center"> Figure 15-1 &nbsp; Greedy strategy for coin change </p>
@ -3921,7 +3921,7 @@
<p>You might exclaim: So clean! The greedy algorithm solves the coin change problem in about ten lines of code.</p>
<h2 id="1511-advantages-and-limitations-of-greedy-algorithms">15.1.1 &nbsp; Advantages and limitations of greedy algorithms<a class="headerlink" href="#1511-advantages-and-limitations-of-greedy-algorithms" title="Permanent link">&para;</a></h2>
<p><strong>Greedy algorithms are not only straightforward and simple to implement, but they are also usually very efficient</strong>. In the code above, if the smallest coin denomination is <span class="arithmatex">\(\min(coins)\)</span>, the greedy choice loops at most <span class="arithmatex">\(amt / \min(coins)\)</span> times, giving a time complexity of <span class="arithmatex">\(O(amt / \min(coins))\)</span>. This is an order of magnitude smaller than the time complexity of the dynamic programming solution, which is <span class="arithmatex">\(O(n \times amt)\)</span>.</p>
<p>However, <strong>for some combinations of coin denominations, greedy algorithms cannot find the optimal solution</strong>. The following figure provides two examples.</p>
<p>However, <strong>for some combinations of coin denominations, greedy algorithms cannot find the optimal solution</strong>. Figure 15-2 provides two examples.</p>
<ul>
<li><strong>Positive example <span class="arithmatex">\(coins = [1, 5, 10, 20, 50, 100]\)</span></strong>: In this coin combination, given any <span class="arithmatex">\(amt\)</span>, the greedy algorithm can find the optimal solution.</li>
<li><strong>Negative example <span class="arithmatex">\(coins = [1, 20, 50]\)</span></strong>: Suppose <span class="arithmatex">\(amt = 60\)</span>, the greedy algorithm can only find the combination <span class="arithmatex">\(50 + 1 \times 10\)</span>, totaling 11 coins, but dynamic programming can find the optimal solution of <span class="arithmatex">\(20 + 20 + 20\)</span>, needing only 3 coins.</li>

View File

@ -3613,7 +3613,7 @@
<p class="admonition-title">Question</p>
<p>Input an array <span class="arithmatex">\(ht\)</span>, where each element represents the height of a vertical partition. Any two partitions in the array, along with the space between them, can form a container.</p>
<p>The capacity of the container is the product of the height and the width (area), where the height is determined by the shorter partition, and the width is the difference in array indices between the two partitions.</p>
<p>Please select two partitions in the array that maximize the container's capacity and return this maximum capacity. An example is shown in the following figure.</p>
<p>Please select two partitions in the array that maximize the container's capacity and return this maximum capacity. An example is shown in Figure 15-7.</p>
</div>
<p><a class="glightbox" href="../max_capacity_problem.assets/max_capacity_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example data for the maximum capacity problem" class="animation-figure" src="../max_capacity_problem.assets/max_capacity_example.png" /></a></p>
<p align="center"> Figure 15-7 &nbsp; Example data for the maximum capacity problem </p>
@ -3625,21 +3625,21 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
\]</div>
<p>Assuming the length of the array is <span class="arithmatex">\(n\)</span>, the number of combinations of two partitions (total number of states) is <span class="arithmatex">\(C_n^2 = \frac{n(n - 1)}{2}\)</span>. The most straightforward approach is to <strong>enumerate all possible states</strong>, resulting in a time complexity of <span class="arithmatex">\(O(n^2)\)</span>.</p>
<h3 id="1-determination-of-a-greedy-strategy">1. &nbsp; Determination of a greedy strategy<a class="headerlink" href="#1-determination-of-a-greedy-strategy" title="Permanent link">&para;</a></h3>
<p>There is a more efficient solution to this problem. As shown in the following figure, we select a state <span class="arithmatex">\([i, j]\)</span> where the indices <span class="arithmatex">\(i &lt; j\)</span> and the height <span class="arithmatex">\(ht[i] &lt; ht[j]\)</span>, meaning <span class="arithmatex">\(i\)</span> is the shorter partition, and <span class="arithmatex">\(j\)</span> is the taller one.</p>
<p>There is a more efficient solution to this problem. As shown in Figure 15-8, we select a state <span class="arithmatex">\([i, j]\)</span> where the indices <span class="arithmatex">\(i &lt; j\)</span> and the height <span class="arithmatex">\(ht[i] &lt; ht[j]\)</span>, meaning <span class="arithmatex">\(i\)</span> is the shorter partition, and <span class="arithmatex">\(j\)</span> is the taller one.</p>
<p><a class="glightbox" href="../max_capacity_problem.assets/max_capacity_initial_state.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Initial state" class="animation-figure" src="../max_capacity_problem.assets/max_capacity_initial_state.png" /></a></p>
<p align="center"> Figure 15-8 &nbsp; Initial state </p>
<p>As shown in the following figure, <strong>if we move the taller partition <span class="arithmatex">\(j\)</span> closer to the shorter partition <span class="arithmatex">\(i\)</span>, the capacity will definitely decrease</strong>.</p>
<p>As shown in Figure 15-9, <strong>if we move the taller partition <span class="arithmatex">\(j\)</span> closer to the shorter partition <span class="arithmatex">\(i\)</span>, the capacity will definitely decrease</strong>.</p>
<p>This is because when moving the taller partition <span class="arithmatex">\(j\)</span>, the width <span class="arithmatex">\(j-i\)</span> definitely decreases; and since the height is determined by the shorter partition, the height can only remain the same (if <span class="arithmatex">\(i\)</span> remains the shorter partition) or decrease (if the moved <span class="arithmatex">\(j\)</span> becomes the shorter partition).</p>
<p><a class="glightbox" href="../max_capacity_problem.assets/max_capacity_moving_long_board.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="State after moving the taller partition inward" class="animation-figure" src="../max_capacity_problem.assets/max_capacity_moving_long_board.png" /></a></p>
<p align="center"> Figure 15-9 &nbsp; State after moving the taller partition inward </p>
<p>Conversely, <strong>we can only possibly increase the capacity by moving the shorter partition <span class="arithmatex">\(i\)</span> inward</strong>. Although the width will definitely decrease, <strong>the height may increase</strong> (if the moved shorter partition <span class="arithmatex">\(i\)</span> becomes taller). For example, in the Figure 15-10 , the area increases after moving the shorter partition.</p>
<p>Conversely, <strong>we can only possibly increase the capacity by moving the shorter partition <span class="arithmatex">\(i\)</span> inward</strong>. Although the width will definitely decrease, <strong>the height may increase</strong> (if the moved shorter partition <span class="arithmatex">\(i\)</span> becomes taller). For example, in Figure 15-10, the area increases after moving the shorter partition.</p>
<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="State after moving the shorter partition inward" class="animation-figure" src="../max_capacity_problem.assets/max_capacity_moving_short_board.png" /></a></p>
<p align="center"> Figure 15-10 &nbsp; State after moving the shorter partition inward </p>
<p>This leads us to the greedy strategy for this problem: initialize two pointers at the ends of the container, and in each round, move the pointer corresponding to the shorter partition inward until the two pointers meet.</p>
<p>The following figures illustrate the execution of the greedy strategy.</p>
<p>Figure 15-11 illustrate the execution of the greedy strategy.</p>
<ol>
<li>Initially, the pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span> are positioned at the ends of the array.</li>
<li>Calculate the current state's capacity <span class="arithmatex">\(cap[i, j]\)</span> and update the maximum capacity.</li>
@ -3979,7 +3979,7 @@ cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
</details>
<h3 id="3-proof-of-correctness">3. &nbsp; Proof of correctness<a class="headerlink" href="#3-proof-of-correctness" title="Permanent link">&para;</a></h3>
<p>The reason why the greedy method is faster than enumeration is that each round of greedy selection "skips" some states.</p>
<p>For example, under the state <span class="arithmatex">\(cap[i, j]\)</span> where <span class="arithmatex">\(i\)</span> is the shorter partition and <span class="arithmatex">\(j\)</span> is the taller partition, greedily moving the shorter partition <span class="arithmatex">\(i\)</span> inward by one step leads to the "skipped" states shown below. <strong>This means that these states' capacities cannot be verified later</strong>.</p>
<p>For example, under the state <span class="arithmatex">\(cap[i, j]\)</span> where <span class="arithmatex">\(i\)</span> is the shorter partition and <span class="arithmatex">\(j\)</span> is the taller partition, greedily moving the shorter partition <span class="arithmatex">\(i\)</span> inward by one step leads to the "skipped" states shown in Figure 15-12. <strong>This means that these states' capacities cannot be verified later</strong>.</p>
<div class="arithmatex">\[
cap[i, i+1], cap[i, i+2], \dots, cap[i, j-2], cap[i, j-1]
\]</div>

View File

@ -3634,13 +3634,13 @@ n = \sum_{i=1}^{m}n_i
n &amp; \geq 4
\end{aligned}
\]</div>
<p>As shown below, when <span class="arithmatex">\(n \geq 4\)</span>, splitting out a <span class="arithmatex">\(2\)</span> increases the product, <strong>which indicates that integers greater than or equal to <span class="arithmatex">\(4\)</span> should be split</strong>.</p>
<p>As shown in Figure 15-14, when <span class="arithmatex">\(n \geq 4\)</span>, splitting out a <span class="arithmatex">\(2\)</span> increases the product, <strong>which indicates that integers greater than or equal to <span class="arithmatex">\(4\)</span> should be split</strong>.</p>
<p><strong>Greedy strategy one</strong>: If the splitting scheme includes factors <span class="arithmatex">\(\geq 4\)</span>, they should be further split. The final split should only include factors <span class="arithmatex">\(1\)</span>, <span class="arithmatex">\(2\)</span>, and <span class="arithmatex">\(3\)</span>.</p>
<p><a class="glightbox" href="../max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Product increase due to splitting" class="animation-figure" src="../max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png" /></a></p>
<p align="center"> Figure 15-14 &nbsp; Product increase due to splitting </p>
<p>Next, consider which factor is optimal. Among the factors <span class="arithmatex">\(1\)</span>, <span class="arithmatex">\(2\)</span>, and <span class="arithmatex">\(3\)</span>, clearly <span class="arithmatex">\(1\)</span> is the worst, as <span class="arithmatex">\(1 \times (n-1) &lt; n\)</span> always holds, meaning splitting out <span class="arithmatex">\(1\)</span> actually decreases the product.</p>
<p>As shown below, when <span class="arithmatex">\(n = 6\)</span>, <span class="arithmatex">\(3 \times 3 &gt; 2 \times 2 \times 2\)</span>. <strong>This means splitting out <span class="arithmatex">\(3\)</span> is better than splitting out <span class="arithmatex">\(2\)</span></strong>.</p>
<p>As shown in Figure 15-15, when <span class="arithmatex">\(n = 6\)</span>, <span class="arithmatex">\(3 \times 3 &gt; 2 \times 2 \times 2\)</span>. <strong>This means splitting out <span class="arithmatex">\(3\)</span> is better than splitting out <span class="arithmatex">\(2\)</span></strong>.</p>
<p><strong>Greedy strategy two</strong>: In the splitting scheme, there should be at most two <span class="arithmatex">\(2\)</span>s. Because three <span class="arithmatex">\(2\)</span>s can always be replaced by two <span class="arithmatex">\(3\)</span>s to obtain a higher product.</p>
<p><a class="glightbox" href="../max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Optimal splitting factors" class="animation-figure" src="../max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png" /></a></p>
<p align="center"> Figure 15-15 &nbsp; Optimal splitting factors </p>
@ -3653,7 +3653,7 @@ n &amp; \geq 4
<li>When the remainder is <span class="arithmatex">\(1\)</span>, since <span class="arithmatex">\(2 \times 2 &gt; 1 \times 3\)</span>, the last <span class="arithmatex">\(3\)</span> should be replaced with <span class="arithmatex">\(2\)</span>.</li>
</ol>
<h3 id="2-code-implementation">2. &nbsp; Code implementation<a class="headerlink" href="#2-code-implementation" title="Permanent link">&para;</a></h3>
<p>As shown below, we do not need to use loops to split the integer but can use the floor division operation to get the number of <span class="arithmatex">\(3\)</span>s, <span class="arithmatex">\(a\)</span>, and the modulo operation to get the remainder, <span class="arithmatex">\(b\)</span>, thus:</p>
<p>As shown in Figure 15-16, we do not need to use loops to split the integer but can use the floor division operation to get the number of <span class="arithmatex">\(3\)</span>s, <span class="arithmatex">\(a\)</span>, and the modulo operation to get the remainder, <span class="arithmatex">\(b\)</span>, thus:</p>
<div class="arithmatex">\[
n = 3a + b
\]</div>

View File

@ -3610,7 +3610,7 @@
<!-- Page content -->
<h1 id="63-hash-algorithms">6.3 &nbsp; Hash algorithms<a class="headerlink" href="#63-hash-algorithms" title="Permanent link">&para;</a></h1>
<p>The previous two sections introduced the working principle of hash tables and the methods to handle hash collisions. However, both open addressing and chaining can <strong>only ensure that the hash table functions normally when collisions occur, but cannot reduce the frequency of hash collisions</strong>.</p>
<p>If hash collisions occur too frequently, the performance of the hash table will deteriorate drastically. As shown in the Figure 6-8 , for a chaining hash table, in the ideal case, the key-value pairs are evenly distributed across the buckets, achieving optimal query efficiency; in the worst case, all key-value pairs are stored in the same bucket, degrading the time complexity to <span class="arithmatex">\(O(n)\)</span>.</p>
<p>If hash collisions occur too frequently, the performance of the hash table will deteriorate drastically. As shown in Figure 6-8, for a chaining hash table, in the ideal case, the key-value pairs are evenly distributed across the buckets, achieving optimal query efficiency; in the worst case, all key-value pairs are stored in the same bucket, degrading the time complexity to <span class="arithmatex">\(O(n)\)</span>.</p>
<p><a class="glightbox" href="../hash_algorithm.assets/hash_collision_best_worst_condition.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Ideal and worst cases of hash collisions" class="animation-figure" src="../hash_algorithm.assets/hash_collision_best_worst_condition.png" /></a></p>
<p align="center"> Figure 6-8 &nbsp; Ideal and worst cases of hash collisions </p>
@ -4252,7 +4252,7 @@
<h2 id="633-common-hash-algorithms">6.3.3 &nbsp; Common hash algorithms<a class="headerlink" href="#633-common-hash-algorithms" title="Permanent link">&para;</a></h2>
<p>It is not hard to see that the simple hash algorithms mentioned above are quite "fragile" and far from reaching the design goals of hash algorithms. For example, since addition and XOR obey the commutative law, additive hash and XOR hash cannot distinguish strings with the same content but in different order, which may exacerbate hash collisions and cause security issues.</p>
<p>In practice, we usually use some standard hash algorithms, such as MD5, SHA-1, SHA-2, and SHA-3. They can map input data of any length to a fixed-length hash value.</p>
<p>Over the past century, hash algorithms have been in a continuous process of upgrading and optimization. Some researchers strive to improve the performance of hash algorithms, while others, including hackers, are dedicated to finding security issues in hash algorithms. The Table 6-2 shows hash algorithms commonly used in practical applications.</p>
<p>Over the past century, hash algorithms have been in a continuous process of upgrading and optimization. Some researchers strive to improve the performance of hash algorithms, while others, including hackers, are dedicated to finding security issues in hash algorithms. Table 6-2 shows hash algorithms commonly used in practical applications.</p>
<ul>
<li>MD5 and SHA-1 have been successfully attacked multiple times and are thus abandoned in various security applications.</li>
<li>SHA-2 series, especially SHA-256, is one of the most secure hash algorithms to date, with no successful attacks reported, hence commonly used in various security applications and protocols.</li>

View File

@ -3683,7 +3683,7 @@
</ol>
<p>There are mainly two methods for improving the structure of hash tables: "Separate Chaining" and "Open Addressing".</p>
<h2 id="621-separate-chaining">6.2.1 &nbsp; Separate chaining<a class="headerlink" href="#621-separate-chaining" title="Permanent link">&para;</a></h2>
<p>In the original hash table, each bucket can store only one key-value pair. "Separate chaining" transforms individual elements into a linked list, with key-value pairs as list nodes, storing all colliding key-value pairs in the same list. The Figure 6-5 shows an example of a hash table with separate chaining.</p>
<p>In the original hash table, each bucket can store only one key-value pair. "Separate chaining" transforms individual elements into a linked list, with key-value pairs as list nodes, storing all colliding key-value pairs in the same list. Figure 6-5 shows an example of a hash table with separate chaining.</p>
<p><a class="glightbox" href="../hash_collision.assets/hash_table_chaining.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Separate chaining hash table" class="animation-figure" src="../hash_collision.assets/hash_table_chaining.png" /></a></p>
<p align="center"> Figure 6-5 &nbsp; Separate chaining hash table </p>
@ -5184,12 +5184,12 @@
<li><strong>Inserting elements</strong>: Calculate the bucket index using the hash function. If the bucket already contains an element, linearly traverse forward from the conflict position (usually with a step size of <span class="arithmatex">\(1\)</span>) until an empty bucket is found, then insert the element.</li>
<li><strong>Searching for elements</strong>: If a hash collision is found, use the same step size to linearly traverse forward until the corresponding element is found and return <code>value</code>; if an empty bucket is encountered, it means the target element is not in the hash table, so return <code>None</code>.</li>
</ul>
<p>The Figure 6-6 shows the distribution of key-value pairs in an open addressing (linear probing) hash table. According to this hash function, keys with the same last two digits will be mapped to the same bucket. Through linear probing, they are stored consecutively in that bucket and the buckets below it.</p>
<p>Figure 6-6 shows the distribution of key-value pairs in an open addressing (linear probing) hash table. According to this hash function, keys with the same last two digits will be mapped to the same bucket. Through linear probing, they are stored consecutively in that bucket and the buckets below it.</p>
<p><a class="glightbox" href="../hash_collision.assets/hash_table_linear_probing.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Distribution of key-value pairs in open addressing (linear probing) hash table" class="animation-figure" src="../hash_collision.assets/hash_table_linear_probing.png" /></a></p>
<p align="center"> Figure 6-6 &nbsp; Distribution of key-value pairs in open addressing (linear probing) hash table </p>
<p>However, <strong>linear probing tends to create "clustering"</strong>. Specifically, the longer a continuous position in the array is occupied, the more likely these positions are to encounter hash collisions, further promoting the growth of these clusters and eventually leading to deterioration in the efficiency of operations.</p>
<p>It's important to note that <strong>we cannot directly delete elements in an open addressing hash table</strong>. Deleting an element creates an empty bucket <code>None</code> in the array. When searching for elements, if linear probing encounters this empty bucket, it will return, making the elements below this bucket inaccessible. The program may incorrectly assume these elements do not exist, as shown in the Figure 6-7 .</p>
<p>It's important to note that <strong>we cannot directly delete elements in an open addressing hash table</strong>. Deleting an element creates an empty bucket <code>None</code> in the array. When searching for elements, if linear probing encounters this empty bucket, it will return, making the elements below this bucket inaccessible. The program may incorrectly assume these elements do not exist, as shown in Figure 6-7.</p>
<p><a class="glightbox" href="../hash_collision.assets/hash_table_open_addressing_deletion.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Query issues caused by deletion in open addressing" class="animation-figure" src="../hash_collision.assets/hash_table_open_addressing_deletion.png" /></a></p>
<p align="center"> Figure 6-7 &nbsp; Query issues caused by deletion in open addressing </p>

View File

@ -3610,11 +3610,11 @@
<!-- Page content -->
<h1 id="61-hash-table">6.1 &nbsp; Hash table<a class="headerlink" href="#61-hash-table" title="Permanent link">&para;</a></h1>
<p>A "hash table", also known as a "hash map", achieves efficient element querying by establishing a mapping between keys and values. Specifically, when we input a <code>key</code> into the hash table, we can retrieve the corresponding <code>value</code> in <span class="arithmatex">\(O(1)\)</span> time.</p>
<p>As shown in the Figure 6-1 , given <span class="arithmatex">\(n\)</span> students, each with two pieces of data: "name" and "student number". If we want to implement a query feature that returns the corresponding name when given a student number, we can use the hash table shown in the Figure 6-1 .</p>
<p>As shown in Figure 6-1, given <span class="arithmatex">\(n\)</span> students, each with two pieces of data: "name" and "student number". If we want to implement a query feature that returns the corresponding name when given a student number, we can use the hash table shown in Figure 6-1.</p>
<p><a class="glightbox" href="../hash_map.assets/hash_table_lookup.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Abstract representation of a hash table" class="animation-figure" src="../hash_map.assets/hash_table_lookup.png" /></a></p>
<p align="center"> Figure 6-1 &nbsp; Abstract representation of a hash table </p>
<p>Apart from hash tables, arrays and linked lists can also be used to implement querying functions. Their efficiency is compared in the Table 6-1 .</p>
<p>Apart from hash tables, arrays and linked lists can also be used to implement querying functions. Their efficiency is compared in Table 6-1.</p>
<ul>
<li><strong>Adding elements</strong>: Simply add the element to the end of the array (or linked list), using <span class="arithmatex">\(O(1)\)</span> time.</li>
<li><strong>Querying elements</strong>: Since the array (or linked list) is unordered, it requires traversing all the elements, using <span class="arithmatex">\(O(n)\)</span> time.</li>
@ -4083,7 +4083,7 @@
<div class="highlight"><pre><span></span><code><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><span class="nv">index</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>hash<span class="o">(</span>key<span class="o">)</span><span class="w"> </span>%<span class="w"> </span>capacity
</code></pre></div>
<p>Afterward, we can use <code>index</code> to access the corresponding bucket in the hash table and thereby retrieve the <code>value</code>.</p>
<p>Assuming array length <code>capacity = 100</code> and hash algorithm <code>hash(key) = key</code>, the hash function is <code>key % 100</code>. The Figure 6-2 uses <code>key</code> as the student number and <code>value</code> as the name to demonstrate the working principle of the hash function.</p>
<p>Assuming array length <code>capacity = 100</code> and hash algorithm <code>hash(key) = key</code>, the hash function is <code>key % 100</code>. Figure 6-2 uses <code>key</code> as the student number and <code>value</code> as the name to demonstrate the working principle of the hash function.</p>
<p><a class="glightbox" href="../hash_map.assets/hash_function.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Working principle of hash function" class="animation-figure" src="../hash_map.assets/hash_function.png" /></a></p>
<p align="center"> Figure 6-2 &nbsp; Working principle of hash function </p>
@ -5362,12 +5362,12 @@
<div class="highlight"><pre><span></span><code><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a><span class="m">12836</span><span class="w"> </span>%<span class="w"> </span><span class="nv">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">36</span>
<a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a><span class="m">20336</span><span class="w"> </span>%<span class="w"> </span><span class="nv">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">36</span>
</code></pre></div>
<p>As shown in the Figure 6-3 , both student numbers point to the same name, which is obviously incorrect. This situation where multiple inputs correspond to the same output is known as "hash collision".</p>
<p>As shown in Figure 6-3, both student numbers point to the same name, which is obviously incorrect. This situation where multiple inputs correspond to the same output is known as "hash collision".</p>
<p><a class="glightbox" href="../hash_map.assets/hash_collision.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example of hash collision" class="animation-figure" src="../hash_map.assets/hash_collision.png" /></a></p>
<p align="center"> Figure 6-3 &nbsp; Example of hash collision </p>
<p>It is easy to understand that the larger the capacity <span class="arithmatex">\(n\)</span> of the hash table, the lower the probability of multiple keys being allocated to the same bucket, and the fewer the collisions. Therefore, <strong>expanding the capacity of the hash table can reduce hash collisions</strong>.</p>
<p>As shown in the Figure 6-4 , before expansion, key-value pairs <code>(136, A)</code> and <code>(236, D)</code> collided; after expansion, the collision is resolved.</p>
<p>As shown in Figure 6-4, before expansion, key-value pairs <code>(136, A)</code> and <code>(236, D)</code> collided; after expansion, the collision is resolved.</p>
<p><a class="glightbox" href="../hash_map.assets/hash_table_reshash.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Hash table expansion" class="animation-figure" src="../hash_map.assets/hash_table_reshash.png" /></a></p>
<p align="center"> Figure 6-4 &nbsp; Hash table expansion </p>

View File

@ -3919,7 +3919,7 @@
<p><a class="glightbox" href="../build_heap.assets/heapify_operations_count.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Node counts at each level of a perfect binary tree" class="animation-figure" src="../build_heap.assets/heapify_operations_count.png" /></a></p>
<p align="center"> Figure 8-5 &nbsp; Node counts at each level of a perfect binary tree </p>
<p>As shown in the Figure 8-5 , the maximum number of iterations for a node "to be heapified from top to bottom" is equal to the distance from that node to the leaf nodes, which is precisely "node height." Therefore, we can sum the "number of nodes <span class="arithmatex">\(\times\)</span> node height" at each level, <strong>to get the total number of heapification iterations for all nodes</strong>.</p>
<p>As shown in Figure 8-5, the maximum number of iterations for a node "to be heapified from top to bottom" is equal to the distance from that node to the leaf nodes, which is precisely "node height." Therefore, we can sum the "number of nodes <span class="arithmatex">\(\times\)</span> node height" at each level, <strong>to get the total number of heapification iterations for all nodes</strong>.</p>
<div class="arithmatex">\[
T(h) = 2^0h + 2^1(h-1) + 2^2(h-2) + \dots + 2^{(h-1)}\times1
\]</div>

View File

@ -3693,7 +3693,7 @@
<!-- Page content -->
<h1 id="81-heap">8.1 &nbsp; Heap<a class="headerlink" href="#81-heap" title="Permanent link">&para;</a></h1>
<p>A "heap" is a complete binary tree that satisfies specific conditions and can be mainly divided into two types, as shown in the Figure 8-1 .</p>
<p>A "heap" is a complete binary tree that satisfies specific conditions and can be mainly divided into two types, as shown in Figure 8-1.</p>
<ul>
<li>"Min heap": The value of any node <span class="arithmatex">\(\leq\)</span> the values of its child nodes.</li>
<li>"Max heap": The value of any node <span class="arithmatex">\(\geq\)</span> the values of its child nodes.</li>
@ -3710,7 +3710,7 @@
<h2 id="811-common-operations-on-heaps">8.1.1 &nbsp; Common operations on heaps<a class="headerlink" href="#811-common-operations-on-heaps" title="Permanent link">&para;</a></h2>
<p>It should be noted that many programming languages provide a "priority queue," which is an abstract data structure defined as a queue with priority sorting.</p>
<p>In fact, <strong>heaps are often used to implement priority queues, with max heaps equivalent to priority queues where elements are dequeued in descending order</strong>. From a usage perspective, we can consider "priority queue" and "heap" as equivalent data structures. Therefore, this book does not make a special distinction between the two, uniformly referring to them as "heap."</p>
<p>Common operations on heaps are shown in the Table 8-1 , and the method names depend on the programming language.</p>
<p>Common operations on heaps are shown in Table 8-1, and the method names depend on the programming language.</p>
<p align="center"> Table 8-1 &nbsp; Efficiency of Heap Operations </p>
<div class="center-table">
@ -4117,7 +4117,7 @@
<h3 id="1-storage-and-representation-of-heaps">1. &nbsp; Storage and representation of heaps<a class="headerlink" href="#1-storage-and-representation-of-heaps" title="Permanent link">&para;</a></h3>
<p>As mentioned in the "Binary Trees" section, complete binary trees are well-suited for array representation. Since heaps are a type of complete binary tree, <strong>we will use arrays to store heaps</strong>.</p>
<p>When using an array to represent a binary tree, elements represent node values, and indexes represent node positions in the binary tree. <strong>Node pointers are implemented through an index mapping formula</strong>.</p>
<p>As shown in the Figure 8-2 , given an index <span class="arithmatex">\(i\)</span>, the index of its left child is <span class="arithmatex">\(2i + 1\)</span>, the index of its right child is <span class="arithmatex">\(2i + 2\)</span>, and the index of its parent is <span class="arithmatex">\((i - 1) / 2\)</span> (floor division). When the index is out of bounds, it signifies a null node or the node does not exist.</p>
<p>As shown in Figure 8-2, given an index <span class="arithmatex">\(i\)</span>, the index of its left child is <span class="arithmatex">\(2i + 1\)</span>, the index of its right child is <span class="arithmatex">\(2i + 2\)</span>, and the index of its parent is <span class="arithmatex">\((i - 1) / 2\)</span> (floor division). When the index is out of bounds, it signifies a null node or the node does not exist.</p>
<p><a class="glightbox" href="../heap.assets/representation_of_heap.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Representation and storage of heaps" class="animation-figure" src="../heap.assets/representation_of_heap.png" /></a></p>
<p align="center"> Figure 8-2 &nbsp; Representation and storage of heaps </p>
@ -4473,7 +4473,7 @@
</details>
<h3 id="3-inserting-an-element-into-the-heap">3. &nbsp; Inserting an element into the heap<a class="headerlink" href="#3-inserting-an-element-into-the-heap" title="Permanent link">&para;</a></h3>
<p>Given an element <code>val</code>, we first add it to the bottom of the heap. After addition, since <code>val</code> may be larger than other elements in the heap, the heap's integrity might be compromised, <strong>thus it's necessary to repair the path from the inserted node to the root node</strong>. This operation is called "heapifying".</p>
<p>Considering starting from the node inserted, <strong>perform heapify from bottom to top</strong>. As shown in the Figure 8-3 , we compare the value of the inserted node with its parent node, and if the inserted node is larger, we swap them. Then continue this operation, repairing each node in the heap from bottom to top until passing the root node or encountering a node that does not need to be swapped.</p>
<p>Considering starting from the node inserted, <strong>perform heapify from bottom to top</strong>. As shown in Figure 8-3, we compare the value of the inserted node with its parent node, and if the inserted node is larger, we swap them. Then continue this operation, repairing each node in the heap from bottom to top until passing the root node or encountering a node that does not need to be swapped.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:9"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><input id="__tabbed_4_6" name="__tabbed_4" type="radio" /><input id="__tabbed_4_7" name="__tabbed_4" type="radio" /><input id="__tabbed_4_8" name="__tabbed_4" type="radio" /><input id="__tabbed_4_9" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">&lt;1&gt;</label><label for="__tabbed_4_2">&lt;2&gt;</label><label for="__tabbed_4_3">&lt;3&gt;</label><label for="__tabbed_4_4">&lt;4&gt;</label><label for="__tabbed_4_5">&lt;5&gt;</label><label for="__tabbed_4_6">&lt;6&gt;</label><label for="__tabbed_4_7">&lt;7&gt;</label><label for="__tabbed_4_8">&lt;8&gt;</label><label for="__tabbed_4_9">&lt;9&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -4886,7 +4886,7 @@
<li>After swapping, remove the bottom of the heap from the list (note, since it has been swapped, what is actually being removed is the original top element).</li>
<li>Starting from the root node, <strong>perform heapify from top to bottom</strong>.</li>
</ol>
<p>As shown in the Figure 8-4 , <strong>the direction of "heapify from top to bottom" is opposite to "heapify from bottom to top"</strong>. We compare the value of the root node with its two children and swap it with the largest child. Then repeat this operation until passing the leaf node or encountering a node that does not need to be swapped.</p>
<p>As shown in Figure 8-4, <strong>the direction of "heapify from top to bottom" is opposite to "heapify from bottom to top"</strong>. We compare the value of the root node with its two children and swap it with the largest child. Then repeat this operation until passing the leaf node or encountering a node that does not need to be swapped.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="6:10"><input checked="checked" id="__tabbed_6_1" name="__tabbed_6" type="radio" /><input id="__tabbed_6_2" name="__tabbed_6" type="radio" /><input id="__tabbed_6_3" name="__tabbed_6" type="radio" /><input id="__tabbed_6_4" name="__tabbed_6" type="radio" /><input id="__tabbed_6_5" name="__tabbed_6" type="radio" /><input id="__tabbed_6_6" name="__tabbed_6" type="radio" /><input id="__tabbed_6_7" name="__tabbed_6" type="radio" /><input id="__tabbed_6_8" name="__tabbed_6" type="radio" /><input id="__tabbed_6_9" name="__tabbed_6" type="radio" /><input id="__tabbed_6_10" name="__tabbed_6" type="radio" /><div class="tabbed-labels"><label for="__tabbed_6_1">&lt;1&gt;</label><label for="__tabbed_6_2">&lt;2&gt;</label><label for="__tabbed_6_3">&lt;3&gt;</label><label for="__tabbed_6_4">&lt;4&gt;</label><label for="__tabbed_6_5">&lt;5&gt;</label><label for="__tabbed_6_6">&lt;6&gt;</label><label for="__tabbed_6_7">&lt;7&gt;</label><label for="__tabbed_6_8">&lt;8&gt;</label><label for="__tabbed_6_9">&lt;9&gt;</label><label for="__tabbed_6_10">&lt;10&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -3615,7 +3615,7 @@
</div>
<p>For this problem, we will first introduce two straightforward solutions, then explain a more efficient heap-based method.</p>
<h2 id="831-method-1-iterative-selection">8.3.1 &nbsp; Method 1: Iterative selection<a class="headerlink" href="#831-method-1-iterative-selection" title="Permanent link">&para;</a></h2>
<p>We can perform <span class="arithmatex">\(k\)</span> rounds of iterations as shown in the Figure 8-6 , extracting the <span class="arithmatex">\(1^{st}\)</span>, <span class="arithmatex">\(2^{nd}\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(k^{th}\)</span> largest elements in each round, with a time complexity of <span class="arithmatex">\(O(nk)\)</span>.</p>
<p>We can perform <span class="arithmatex">\(k\)</span> rounds of iterations as shown in Figure 8-6, extracting the <span class="arithmatex">\(1^{st}\)</span>, <span class="arithmatex">\(2^{nd}\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(k^{th}\)</span> largest elements in each round, with a time complexity of <span class="arithmatex">\(O(nk)\)</span>.</p>
<p>This method is only suitable when <span class="arithmatex">\(k \ll n\)</span>, as the time complexity approaches <span class="arithmatex">\(O(n^2)\)</span> when <span class="arithmatex">\(k\)</span> is close to <span class="arithmatex">\(n\)</span>, which is very time-consuming.</p>
<p><a class="glightbox" href="../top_k.assets/top_k_traversal.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Iteratively finding the largest k elements" class="animation-figure" src="../top_k.assets/top_k_traversal.png" /></a></p>
<p align="center"> Figure 8-6 &nbsp; Iteratively finding the largest k elements </p>
@ -3625,7 +3625,7 @@
<p>When <span class="arithmatex">\(k = n\)</span>, we can obtain a complete ordered sequence, which is equivalent to the "selection sort" algorithm.</p>
</div>
<h2 id="832-method-2-sorting">8.3.2 &nbsp; Method 2: Sorting<a class="headerlink" href="#832-method-2-sorting" title="Permanent link">&para;</a></h2>
<p>As shown in the Figure 8-7 , we can first sort the array <code>nums</code> and then return the last <span class="arithmatex">\(k\)</span> elements, with a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>.</p>
<p>As shown in Figure 8-7, we can first sort the array <code>nums</code> and then return the last <span class="arithmatex">\(k\)</span> elements, with a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>.</p>
<p>Clearly, this method "overachieves" the task, as we only need to find the largest <span class="arithmatex">\(k\)</span> elements, without the need to sort the other elements.</p>
<p><a class="glightbox" href="../top_k.assets/top_k_sorting.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Sorting to find the largest k elements" class="animation-figure" src="../top_k.assets/top_k_sorting.png" /></a></p>
<p align="center"> Figure 8-7 &nbsp; Sorting to find the largest k elements </p>

View File

@ -3557,7 +3557,7 @@
<p align="center"> Figure 1-2 &nbsp; Playing cards sorting process </p>
<p>The above method of organizing playing cards is essentially the "Insertion Sort" algorithm, which is very efficient for small datasets. Many programming languages' sorting functions include the insertion sort.</p>
<p><strong>Example 3: Making Change</strong>. Suppose we buy goods worth <span class="arithmatex">\(69\)</span> yuan at a supermarket and give the cashier <span class="arithmatex">\(100\)</span> yuan, then the cashier needs to give us <span class="arithmatex">\(31\)</span> yuan in change. They would naturally complete the thought process as shown below.</p>
<p><strong>Example 3: Making Change</strong>. Suppose we buy goods worth <span class="arithmatex">\(69\)</span> yuan at a supermarket and give the cashier <span class="arithmatex">\(100\)</span> yuan, then the cashier needs to give us <span class="arithmatex">\(31\)</span> yuan in change. They would naturally complete the thought process as shown in Figure 1-3.</p>
<ol>
<li>The options are currencies smaller than <span class="arithmatex">\(31\)</span>, including <span class="arithmatex">\(1\)</span>, <span class="arithmatex">\(5\)</span>, <span class="arithmatex">\(10\)</span>, and <span class="arithmatex">\(20\)</span>.</li>
<li>Take out the largest <span class="arithmatex">\(20\)</span> from the options, leaving <span class="arithmatex">\(31 - 20 = 11\)</span>.</li>

View File

@ -3629,7 +3629,7 @@
<li>Graphs, compared to linked lists, provide richer logical information but require more memory space.</li>
</ul>
<h2 id="123-relationship-between-data-structures-and-algorithms">1.2.3 &nbsp; Relationship between data structures and algorithms<a class="headerlink" href="#123-relationship-between-data-structures-and-algorithms" title="Permanent link">&para;</a></h2>
<p>As shown in the Figure 1-4 , data structures and algorithms are highly related and closely integrated, specifically in the following three aspects:</p>
<p>As shown in Figure 1-4, data structures and algorithms are highly related and closely integrated, specifically in the following three aspects:</p>
<ul>
<li>Data structures are the foundation of algorithms. They provide structured data storage and methods for manipulating data for algorithms.</li>
<li>Algorithms are the stage where data structures come into play. The data structure alone only stores data information; it is through the application of algorithms that specific problems can be solved.</li>
@ -3638,11 +3638,11 @@
<p><a class="glightbox" href="../what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Relationship between data structures and algorithms" class="animation-figure" src="../what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png" /></a></p>
<p align="center"> Figure 1-4 &nbsp; Relationship between data structures and algorithms </p>
<p>Data structures and algorithms can be likened to a set of building blocks, as illustrated in the Figure 1-5 . A building block set includes numerous pieces, accompanied by detailed assembly instructions. Following these instructions step by step allows us to construct an intricate block model.</p>
<p>Data structures and algorithms can be likened to a set of building blocks, as illustrated in Figure 1-5. A building block set includes numerous pieces, accompanied by detailed assembly instructions. Following these instructions step by step allows us to construct an intricate block model.</p>
<p><a class="glightbox" href="../what_is_dsa.assets/assembling_blocks.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Assembling blocks" class="animation-figure" src="../what_is_dsa.assets/assembling_blocks.png" /></a></p>
<p align="center"> Figure 1-5 &nbsp; Assembling blocks </p>
<p>The detailed correspondence between the two is shown in the Table 1-1 .</p>
<p>The detailed correspondence between the two is shown in Table 1-1.</p>
<p align="center"> Table 1-1 &nbsp; Comparing data structures and algorithms to building blocks </p>
<div class="center-table">

View File

@ -3624,7 +3624,7 @@
<p>You should know how to write and read simple code in at least one programming language.</p>
</div>
<h2 id="012-content-structure">0.1.2 &nbsp; Content structure<a class="headerlink" href="#012-content-structure" title="Permanent link">&para;</a></h2>
<p>The main content of the book is shown in the following figure.</p>
<p>The main content of the book is shown in Figure 0-1.</p>
<ul>
<li><strong>Complexity analysis</strong>: explores aspects and methods for evaluating data structures and algorithms. Covers methods of deriving time complexity and space complexity, along with common types and examples.</li>
<li><strong>Data structures</strong>: focuses on fundamental data types, classification methods, definitions, pros and cons, common operations, types, applications, and implementation methods of data structures such as array, linked list, stack, queue, hash table, tree, heap, graph, etc.</li>

View File

@ -3805,12 +3805,12 @@
</div>
<h2 id="022-efficient-learning-via-animated-illustrations">0.2.2 &nbsp; Efficient learning via animated illustrations<a class="headerlink" href="#022-efficient-learning-via-animated-illustrations" title="Permanent link">&para;</a></h2>
<p>Compared with text, videos and pictures have a higher density of information and are more structured, making them easier to understand. In this book, <strong>key and difficult concepts are mainly presented through animations and illustrations</strong>, with text serving as explanations and supplements.</p>
<p>When encountering content with animations or illustrations as shown in the Figure 0-2 , <strong>prioritize understanding the figure, with text as supplementary</strong>, integrating both for a comprehensive understanding.</p>
<p>When encountering content with animations or illustrations as shown in Figure 0-2, <strong>prioritize understanding the figure, with text as supplementary</strong>, integrating both for a comprehensive understanding.</p>
<p><a class="glightbox" href="../../index.assets/animation.gif" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Animated illustration example" class="animation-figure" src="../../index.assets/animation.gif" /></a></p>
<p align="center"> Figure 0-2 &nbsp; Animated illustration example </p>
<h2 id="023-deepen-understanding-through-coding-practice">0.2.3 &nbsp; Deepen understanding through coding practice<a class="headerlink" href="#023-deepen-understanding-through-coding-practice" title="Permanent link">&para;</a></h2>
<p>The source code of this book is hosted on the <a href="https://github.com/krahets/hello-algo">GitHub Repository</a>. As shown in the Figure 0-3 , <strong>the source code comes with test examples and can be executed with just a single click</strong>.</p>
<p>The source code of this book is hosted on the <a href="https://github.com/krahets/hello-algo">GitHub Repository</a>. As shown in Figure 0-3, <strong>the source code comes with test examples and can be executed with just a single click</strong>.</p>
<p>If time permits, <strong>it's recommended to type out the code yourself</strong>. If pressed for time, at least read and run all the codes.</p>
<p>Compared to just reading code, writing code often yields more learning. <strong>Learning by doing is the real way to learn.</strong></p>
<p><a class="glightbox" href="../../index.assets/running_code.gif" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Running code example" class="animation-figure" src="../../index.assets/running_code.gif" /></a></p>
@ -3822,17 +3822,17 @@
<p>If <a href="https://git-scm.com/downloads">Git</a> is installed, use the following command to clone the repository:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/krahets/hello-algo.git
</code></pre></div>
<p>Alternatively, you can also click the "Download ZIP" button at the location shown in the Figure 0-4 to directly download the code as a compressed ZIP file. Then, you can simply extract it locally.</p>
<p>Alternatively, you can also click the "Download ZIP" button at the location shown in Figure 0-4 to directly download the code as a compressed ZIP file. Then, you can simply extract it locally.</p>
<p><a class="glightbox" href="../suggestions.assets/download_code.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Cloning repository and downloading code" class="animation-figure" src="../suggestions.assets/download_code.png" /></a></p>
<p align="center"> Figure 0-4 &nbsp; Cloning repository and downloading code </p>
<p><strong>Step 3: Run the source code</strong>. As shown in the Figure 0-5 , for the code block labeled with the file name at the top, we can find the corresponding source code file in the <code>codes</code> folder of the repository. These files can be executed with a single click, which will help you save unnecessary debugging time and allow you to focus on learning.</p>
<p><strong>Step 3: Run the source code</strong>. As shown in Figure 0-5, for the code block labeled with the file name at the top, we can find the corresponding source code file in the <code>codes</code> folder of the repository. These files can be executed with a single click, which will help you save unnecessary debugging time and allow you to focus on learning.</p>
<p><a class="glightbox" href="../suggestions.assets/code_md_to_repo.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Code block and corresponding source code file" class="animation-figure" src="../suggestions.assets/code_md_to_repo.png" /></a></p>
<p align="center"> Figure 0-5 &nbsp; Code block and corresponding source code file </p>
<h2 id="024-learning-together-in-discussion">0.2.4 &nbsp; Learning together in discussion<a class="headerlink" href="#024-learning-together-in-discussion" title="Permanent link">&para;</a></h2>
<p>While reading this book, please don't skip over the points that you didn't learn. <strong>Feel free to post your questions in the comment section</strong>. We will be happy to answer them and can usually respond within two days.</p>
<p>As illustrated in the Figure 0-6 , each chapter features a comment section at the bottom. I encourage you to pay attention to these comments. They not only expose you to others' encountered problems, aiding in identifying knowledge gaps and sparking deeper contemplation, but also invite you to generously contribute by answering fellow readers' inquiries, sharing insights, and fostering mutual improvement.</p>
<p>As illustrated in Figure 0-6, each chapter features a comment section at the bottom. I encourage you to pay attention to these comments. They not only expose you to others' encountered problems, aiding in identifying knowledge gaps and sparking deeper contemplation, but also invite you to generously contribute by answering fellow readers' inquiries, sharing insights, and fostering mutual improvement.</p>
<p><a class="glightbox" href="../../index.assets/comment.gif" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Comment section example" class="animation-figure" src="../../index.assets/comment.gif" /></a></p>
<p align="center"> Figure 0-6 &nbsp; Comment section example </p>
@ -3843,7 +3843,7 @@
<li><strong>Stage 2: Practicing algorithm problems</strong>. It is recommended to start from popular problems, such as <a href="https://leetcode.cn/studyplan/coding-interviews/">Sword for Offer</a> and <a href="https://leetcode.cn/studyplan/top-100- liked/">LeetCode Hot 100</a>, and accumulate at least 100 questions to familiarize yourself with mainstream algorithmic problems. Forgetfulness can be a challenge when you start practicing, but rest assured that this is normal. We can follow the "Ebbinghaus Forgetting Curve" to review the questions, and usually after 3~5 rounds of repetitions, we will be able to memorize them.</li>
<li><strong>Stage 3: Building the knowledge system</strong>. In terms of learning, we can read algorithm column articles, solution frameworks, and algorithm textbooks to continuously enrich the knowledge system. In terms of practicing, we can try advanced strategies, such as categorizing by topic, multiple solutions for a single problem, and one solution for multiple problems, etc. Insights on these strategies can be found in various communities.</li>
</ol>
<p>As shown in the Figure 0-7 , this book mainly covers “Stage 1,” aiming to help you more efficiently embark on Stages 2 and 3.</p>
<p>As shown in Figure 0-7, this book mainly covers “Stage 1,” aiming to help you more efficiently embark on Stages 2 and 3.</p>
<p><a class="glightbox" href="../suggestions.assets/learning_route.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Algorithm learning path" class="animation-figure" src="../suggestions.assets/learning_route.png" /></a></p>
<p align="center"> Figure 0-7 &nbsp; Algorithm learning path </p>

View File

@ -3594,12 +3594,12 @@
<p><u>Binary search</u> is an efficient search algorithm based on the divide-and-conquer strategy. It utilizes the orderliness of data, reducing the search range by half each round until the target element is found or the search interval is empty.</p>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>Given an array <code>nums</code> of length <span class="arithmatex">\(n\)</span>, with elements arranged in ascending order and non-repeating. Please find and return the index of element <code>target</code> in this array. If the array does not contain the element, return <span class="arithmatex">\(-1\)</span>. An example is shown below.</p>
<p>Given an array <code>nums</code> of length <span class="arithmatex">\(n\)</span>, with elements arranged in ascending order and non-repeating. Please find and return the index of element <code>target</code> in this array. If the array does not contain the element, return <span class="arithmatex">\(-1\)</span>. An example is shown in Figure 10-1.</p>
</div>
<p><a class="glightbox" href="../binary_search.assets/binary_search_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Binary search example data" class="animation-figure" src="../binary_search.assets/binary_search_example.png" /></a></p>
<p align="center"> Figure 10-1 &nbsp; Binary search example data </p>
<p>As shown in the Figure 10-2 , we first initialize pointers <span class="arithmatex">\(i = 0\)</span> and <span class="arithmatex">\(j = n - 1\)</span>, pointing to the first and last elements of the array, representing the search interval <span class="arithmatex">\([0, n - 1]\)</span>. Please note that square brackets indicate a closed interval, which includes the boundary values themselves.</p>
<p>As shown in Figure 10-2, we first initialize pointers <span class="arithmatex">\(i = 0\)</span> and <span class="arithmatex">\(j = n - 1\)</span>, pointing to the first and last elements of the array, representing the search interval <span class="arithmatex">\([0, n - 1]\)</span>. Please note that square brackets indicate a closed interval, which includes the boundary values themselves.</p>
<p>Next, perform the following two steps in a loop.</p>
<ol>
<li>Calculate the midpoint index <span class="arithmatex">\(m = \lfloor {(i + j) / 2} \rfloor\)</span>, where <span class="arithmatex">\(\lfloor \: \rfloor\)</span> denotes the floor operation.</li>
@ -4273,7 +4273,7 @@
<p><div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20binary_search_lcro%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%EF%BC%88%E5%B7%A6%E9%97%AD%E5%8F%B3%E5%BC%80%E5%8C%BA%E9%97%B4%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B7%A6%E9%97%AD%E5%8F%B3%E5%BC%80%E5%8C%BA%E9%97%B4%20%5B0,%20n%29%20%EF%BC%8C%E5%8D%B3%20i,%20j%20%E5%88%86%E5%88%AB%E6%8C%87%E5%90%91%E6%95%B0%E7%BB%84%E9%A6%96%E5%85%83%E7%B4%A0%E3%80%81%E5%B0%BE%E5%85%83%E7%B4%A0%2B1%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%0A%20%20%20%20%23%20%E5%BE%AA%E7%8E%AF%EF%BC%8C%E5%BD%93%E6%90%9C%E7%B4%A2%E5%8C%BA%E9%97%B4%E4%B8%BA%E7%A9%BA%E6%97%B6%E8%B7%B3%E5%87%BA%EF%BC%88%E5%BD%93%20i%20%3D%20j%20%E6%97%B6%E4%B8%BA%E7%A9%BA%EF%BC%89%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E8%AE%A1%E7%AE%97%E4%B8%AD%E7%82%B9%E7%B4%A2%E5%BC%95%20m%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%E6%AD%A4%E6%83%85%E5%86%B5%E8%AF%B4%E6%98%8E%20target%20%E5%9C%A8%E5%8C%BA%E9%97%B4%20%5Bm%2B1,%20j%29%20%E4%B8%AD%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20%20%23%20%E6%AD%A4%E6%83%85%E5%86%B5%E8%AF%B4%E6%98%8E%20target%20%E5%9C%A8%E5%8C%BA%E9%97%B4%20%5Bi,%20m%29%20%E4%B8%AD%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%E6%89%BE%E5%88%B0%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0%EF%BC%8C%E8%BF%94%E5%9B%9E%E5%85%B6%E7%B4%A2%E5%BC%95%0A%20%20%20%20return%20-1%20%20%23%20%E6%9C%AA%E6%89%BE%E5%88%B0%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0%EF%BC%8C%E8%BF%94%E5%9B%9E%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%208,%2012,%2015,%2023,%2026,%2031,%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%EF%BC%88%E5%B7%A6%E9%97%AD%E5%8F%B3%E5%BC%80%E5%8C%BA%E9%97%B4%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search_lcro%28nums,%20target%29%0A%20%20%20%20print%28%22%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0%206%20%E7%9A%84%E7%B4%A2%E5%BC%95%20%3D%20%22,%20index%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20binary_search_lcro%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%EF%BC%88%E5%B7%A6%E9%97%AD%E5%8F%B3%E5%BC%80%E5%8C%BA%E9%97%B4%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B7%A6%E9%97%AD%E5%8F%B3%E5%BC%80%E5%8C%BA%E9%97%B4%20%5B0,%20n%29%20%EF%BC%8C%E5%8D%B3%20i,%20j%20%E5%88%86%E5%88%AB%E6%8C%87%E5%90%91%E6%95%B0%E7%BB%84%E9%A6%96%E5%85%83%E7%B4%A0%E3%80%81%E5%B0%BE%E5%85%83%E7%B4%A0%2B1%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%0A%20%20%20%20%23%20%E5%BE%AA%E7%8E%AF%EF%BC%8C%E5%BD%93%E6%90%9C%E7%B4%A2%E5%8C%BA%E9%97%B4%E4%B8%BA%E7%A9%BA%E6%97%B6%E8%B7%B3%E5%87%BA%EF%BC%88%E5%BD%93%20i%20%3D%20j%20%E6%97%B6%E4%B8%BA%E7%A9%BA%EF%BC%89%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E8%AE%A1%E7%AE%97%E4%B8%AD%E7%82%B9%E7%B4%A2%E5%BC%95%20m%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%E6%AD%A4%E6%83%85%E5%86%B5%E8%AF%B4%E6%98%8E%20target%20%E5%9C%A8%E5%8C%BA%E9%97%B4%20%5Bm%2B1,%20j%29%20%E4%B8%AD%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20%20%23%20%E6%AD%A4%E6%83%85%E5%86%B5%E8%AF%B4%E6%98%8E%20target%20%E5%9C%A8%E5%8C%BA%E9%97%B4%20%5Bi,%20m%29%20%E4%B8%AD%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%E6%89%BE%E5%88%B0%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0%EF%BC%8C%E8%BF%94%E5%9B%9E%E5%85%B6%E7%B4%A2%E5%BC%95%0A%20%20%20%20return%20-1%20%20%23%20%E6%9C%AA%E6%89%BE%E5%88%B0%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0%EF%BC%8C%E8%BF%94%E5%9B%9E%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%208,%2012,%2015,%2023,%2026,%2031,%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%EF%BC%88%E5%B7%A6%E9%97%AD%E5%8F%B3%E5%BC%80%E5%8C%BA%E9%97%B4%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search_lcro%28nums,%20target%29%0A%20%20%20%20print%28%22%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0%206%20%E7%9A%84%E7%B4%A2%E5%BC%95%20%3D%20%22,%20index%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<p>As shown in the Figure 10-3 , in the two types of interval representations, the initialization of the binary search algorithm, the loop condition, and the narrowing interval operation are different.</p>
<p>As shown in Figure 10-3, in the two types of interval representations, the initialization of the binary search algorithm, the loop condition, and the narrowing interval operation are different.</p>
<p>Since both boundaries in the "closed interval" representation are defined as closed, the operations to narrow the interval through pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span> are also symmetrical. This makes it less prone to errors, <strong>therefore, it is generally recommended to use the "closed interval" approach</strong>.</p>
<p><a class="glightbox" href="../binary_search.assets/binary_search_ranges.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Two types of interval definitions" class="animation-figure" src="../binary_search.assets/binary_search_ranges.png" /></a></p>
<p align="center"> Figure 10-3 &nbsp; Two types of interval definitions </p>

View File

@ -3848,7 +3848,7 @@
<p>Below we introduce two more cunning methods.</p>
<h3 id="1-reusing-the-search-for-the-left-boundary">1. &nbsp; Reusing the search for the left boundary<a class="headerlink" href="#1-reusing-the-search-for-the-left-boundary" title="Permanent link">&para;</a></h3>
<p>In fact, we can use the function for finding the leftmost element to find the rightmost element, specifically by <strong>transforming the search for the rightmost <code>target</code> into a search for the leftmost <code>target + 1</code></strong>.</p>
<p>As shown in the Figure 10-7 , after the search is completed, the pointer <span class="arithmatex">\(i\)</span> points to the leftmost <code>target + 1</code> (if it exists), while <span class="arithmatex">\(j\)</span> points to the rightmost <code>target</code>, <strong>thus returning <span class="arithmatex">\(j\)</span> is sufficient</strong>.</p>
<p>As shown in Figure 10-7, after the search is completed, the pointer <span class="arithmatex">\(i\)</span> points to the leftmost <code>target + 1</code> (if it exists), while <span class="arithmatex">\(j\)</span> points to the rightmost <code>target</code>, <strong>thus returning <span class="arithmatex">\(j\)</span> is sufficient</strong>.</p>
<p><a class="glightbox" href="../binary_search_edge.assets/binary_search_right_edge_by_left_edge.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Transforming the search for the right boundary into the search for the left boundary" class="animation-figure" src="../binary_search_edge.assets/binary_search_right_edge_by_left_edge.png" /></a></p>
<p align="center"> Figure 10-7 &nbsp; Transforming the search for the right boundary into the search for the left boundary </p>
@ -4074,7 +4074,7 @@
</details>
<h3 id="2-transforming-into-an-element-search">2. &nbsp; Transforming into an element search<a class="headerlink" href="#2-transforming-into-an-element-search" title="Permanent link">&para;</a></h3>
<p>We know that when the array does not contain <code>target</code>, <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span> will eventually point to the first element greater and smaller than <code>target</code> respectively.</p>
<p>Thus, as shown in the Figure 10-8 , we can construct an element that does not exist in the array, to search for the left and right boundaries.</p>
<p>Thus, as shown in Figure 10-8, we can construct an element that does not exist in the array, to search for the left and right boundaries.</p>
<ul>
<li>To find the leftmost <code>target</code>: it can be transformed into searching for <code>target - 0.5</code>, and return the pointer <span class="arithmatex">\(i\)</span>.</li>
<li>To find the rightmost <code>target</code>: it can be transformed into searching for <code>target + 0.5</code>, and return the pointer <span class="arithmatex">\(j\)</span>.</li>

View File

@ -3595,7 +3595,7 @@
<h2 id="1021-case-with-no-duplicate-elements">10.2.1 &nbsp; Case with no duplicate elements<a class="headerlink" href="#1021-case-with-no-duplicate-elements" title="Permanent link">&para;</a></h2>
<div class="admonition question">
<p class="admonition-title">Question</p>
<p>Given an ordered array <code>nums</code> of length <span class="arithmatex">\(n\)</span> and an element <code>target</code>, where the array has no duplicate elements. Now insert <code>target</code> into the array <code>nums</code> while maintaining its order. If the element <code>target</code> already exists in the array, insert it to its left side. Please return the index of <code>target</code> in the array after insertion. See the example shown in the Figure 10-4 .</p>
<p>Given an ordered array <code>nums</code> of length <span class="arithmatex">\(n\)</span> and an element <code>target</code>, where the array has no duplicate elements. Now insert <code>target</code> into the array <code>nums</code> while maintaining its order. If the element <code>target</code> already exists in the array, insert it to its left side. Please return the index of <code>target</code> in the array after insertion. See the example shown in Figure 10-4.</p>
</div>
<p><a class="glightbox" href="../binary_search_insertion.assets/binary_search_insertion_example.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example data for binary search insertion point" class="animation-figure" src="../binary_search_insertion.assets/binary_search_insertion_example.png" /></a></p>
<p align="center"> Figure 10-4 &nbsp; Example data for binary search insertion point </p>
@ -3886,7 +3886,7 @@
<p>Based on the previous question, assume the array may contain duplicate elements, all else remains the same.</p>
</div>
<p>Suppose there are multiple <code>target</code>s in the array, ordinary binary search can only return the index of one of the <code>target</code>s, <strong>and it cannot determine how many <code>target</code>s are to the left and right of that element</strong>.</p>
<p>The task requires inserting the target element to the very left, <strong>so we need to find the index of the leftmost <code>target</code> in the array</strong>. Initially consider implementing this through the steps shown in the Figure 10-5 .</p>
<p>The task requires inserting the target element to the very left, <strong>so we need to find the index of the leftmost <code>target</code> in the array</strong>. Initially consider implementing this through the steps shown in Figure 10-5.</p>
<ol>
<li>Perform a binary search, get an arbitrary index of <code>target</code>, denoted as <span class="arithmatex">\(k\)</span>.</li>
<li>Start from index <span class="arithmatex">\(k\)</span>, and perform a linear search to the left until the leftmost <code>target</code> is found and return.</li>
@ -3895,7 +3895,7 @@
<p align="center"> Figure 10-5 &nbsp; Linear search for the insertion point of duplicate elements </p>
<p>Although this method is feasible, it includes linear search, so its time complexity is <span class="arithmatex">\(O(n)\)</span>. This method is inefficient when the array contains many duplicate <code>target</code>s.</p>
<p>Now consider extending the binary search code. As shown in the Figure 10-6 , the overall process remains the same, each round first calculates the midpoint index <span class="arithmatex">\(m\)</span>, then judges the size relationship between <code>target</code> and <code>nums[m]</code>, divided into the following cases.</p>
<p>Now consider extending the binary search code. As shown in Figure 10-6, the overall process remains the same, each round first calculates the midpoint index <span class="arithmatex">\(m\)</span>, then judges the size relationship between <code>target</code> and <code>nums[m]</code>, divided into the following cases.</p>
<ul>
<li>When <code>nums[m] &lt; target</code> or <code>nums[m] &gt; target</code>, it means <code>target</code> has not been found yet, thus use the normal binary search interval reduction operation, <strong>thus making pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span> approach <code>target</code></strong>.</li>
<li>When <code>nums[m] == target</code>, it indicates that the elements less than <code>target</code> are in the interval <span class="arithmatex">\([i, m - 1]\)</span>, therefore use <span class="arithmatex">\(j = m - 1\)</span> to narrow the interval, <strong>thus making pointer <span class="arithmatex">\(j\)</span> approach elements less than <code>target</code></strong>.</li>

View File

@ -3597,7 +3597,7 @@
<p>Given an integer array <code>nums</code> and a target element <code>target</code>, please search for two elements in the array whose "sum" equals <code>target</code>, and return their array indices. Any solution is acceptable.</p>
</div>
<h2 id="1041-linear-search-trading-time-for-space">10.4.1 &nbsp; Linear search: trading time for space<a class="headerlink" href="#1041-linear-search-trading-time-for-space" title="Permanent link">&para;</a></h2>
<p>Consider traversing all possible combinations directly. As shown in the Figure 10-9 , we initiate a two-layer loop, and in each round, we determine whether the sum of the two integers equals <code>target</code>. If so, we return their indices.</p>
<p>Consider traversing all possible combinations directly. As shown in Figure 10-9, we initiate a two-layer loop, and in each round, we determine whether the sum of the two integers equals <code>target</code>. If so, we return their indices.</p>
<p><a class="glightbox" href="../replace_linear_by_hashing.assets/two_sum_brute_force.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Linear search solution for two-sum problem" class="animation-figure" src="../replace_linear_by_hashing.assets/two_sum_brute_force.png" /></a></p>
<p align="center"> Figure 10-9 &nbsp; Linear search solution for two-sum problem </p>

View File

@ -3638,7 +3638,7 @@
<p>Adaptive search algorithms are often referred to as search algorithms, <strong>mainly used for quickly retrieving target elements in specific data structures</strong>.</p>
</div>
<h2 id="1053-choosing-a-search-method">10.5.3 &nbsp; Choosing a search method<a class="headerlink" href="#1053-choosing-a-search-method" title="Permanent link">&para;</a></h2>
<p>Given a set of data of size <span class="arithmatex">\(n\)</span>, we can use linear search, binary search, tree search, hash search, and other methods to search for the target element from it. The working principles of these methods are shown in the following figure.</p>
<p>Given a set of data of size <span class="arithmatex">\(n\)</span>, we can use linear search, binary search, tree search, hash search, and other methods to search for the target element from it. The working principles of these methods are shown in Figure 10-11.</p>
<p><a class="glightbox" href="../searching_algorithm_revisited.assets/searching_algorithms.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Various search strategies" class="animation-figure" src="../searching_algorithm_revisited.assets/searching_algorithms.png" /></a></p>
<p align="center"> Figure 10-11 &nbsp; Various search strategies </p>

View File

@ -3610,7 +3610,7 @@
<!-- Page content -->
<h1 id="113-bubble-sort">11.3 &nbsp; Bubble sort<a class="headerlink" href="#113-bubble-sort" title="Permanent link">&para;</a></h1>
<p><u>Bubble sort</u> achieves sorting by continuously comparing and swapping adjacent elements. This process resembles bubbles rising from the bottom to the top, hence the name bubble sort.</p>
<p>As shown in the following figures, the bubbling process can be simulated using element swap operations: starting from the leftmost end of the array and moving right, sequentially compare the size of adjacent elements. If "left element &gt; right element," then swap them. After the traversal, the largest element will be moved to the far right end of the array.</p>
<p>As shown in Figure 11-4, the bubbling process can be simulated using element swap operations: starting from the leftmost end of the array and moving right, sequentially compare the size of adjacent elements. If "left element &gt; right element," then swap them. After the traversal, the largest element will be moved to the far right end of the array.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:7"><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" /><div class="tabbed-labels"><label for="__tabbed_1_1">&lt;1&gt;</label><label for="__tabbed_1_2">&lt;2&gt;</label><label for="__tabbed_1_3">&lt;3&gt;</label><label for="__tabbed_1_4">&lt;4&gt;</label><label for="__tabbed_1_5">&lt;5&gt;</label><label for="__tabbed_1_6">&lt;6&gt;</label><label for="__tabbed_1_7">&lt;7&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -3639,7 +3639,7 @@
<p align="center"> Figure 11-4 &nbsp; Simulating bubble process using element swap </p>
<h2 id="1131-algorithm-process">11.3.1 &nbsp; Algorithm process<a class="headerlink" href="#1131-algorithm-process" title="Permanent link">&para;</a></h2>
<p>Assuming the length of the array is <span class="arithmatex">\(n\)</span>, the steps of bubble sort are shown below.</p>
<p>Assuming the length of the array is <span class="arithmatex">\(n\)</span>, the steps of bubble sort are shown in Figure 11-5.</p>
<ol>
<li>First, perform a "bubble" on <span class="arithmatex">\(n\)</span> elements, <strong>swapping the largest element to its correct position</strong>.</li>
<li>Next, perform a "bubble" on the remaining <span class="arithmatex">\(n - 1\)</span> elements, <strong>swapping the second largest element to its correct position</strong>.</li>

View File

@ -3612,7 +3612,7 @@
<p>The previously mentioned sorting algorithms are all "comparison-based sorting algorithms," which sort by comparing the size of elements. Such sorting algorithms cannot surpass a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>. Next, we will discuss several "non-comparison sorting algorithms" that can achieve linear time complexity.</p>
<p><u>Bucket sort</u> is a typical application of the divide-and-conquer strategy. It involves setting up a series of ordered buckets, each corresponding to a range of data, and then distributing the data evenly among these buckets; each bucket is then sorted individually; finally, all the data are merged in the order of the buckets.</p>
<h2 id="1181-algorithm-process">11.8.1 &nbsp; Algorithm process<a class="headerlink" href="#1181-algorithm-process" title="Permanent link">&para;</a></h2>
<p>Consider an array of length <span class="arithmatex">\(n\)</span>, with elements in the range <span class="arithmatex">\([0, 1)\)</span>. The bucket sort process is illustrated in the Figure 11-13 .</p>
<p>Consider an array of length <span class="arithmatex">\(n\)</span>, with elements in the range <span class="arithmatex">\([0, 1)\)</span>. The bucket sort process is illustrated in Figure 11-13.</p>
<ol>
<li>Initialize <span class="arithmatex">\(k\)</span> buckets and distribute <span class="arithmatex">\(n\)</span> elements into these <span class="arithmatex">\(k\)</span> buckets.</li>
<li>Sort each bucket individually (using the built-in sorting function of the programming language).</li>
@ -4035,12 +4035,12 @@
<h2 id="1183-how-to-achieve-even-distribution">11.8.3 &nbsp; How to achieve even distribution<a class="headerlink" href="#1183-how-to-achieve-even-distribution" title="Permanent link">&para;</a></h2>
<p>The theoretical time complexity of bucket sort can reach <span class="arithmatex">\(O(n)\)</span>, <strong>the key is to evenly distribute the elements across all buckets</strong>, as real data is often not uniformly distributed. For example, if we want to evenly distribute all products on Taobao by price range into 10 buckets, but the distribution of product prices is uneven, with many under 100 yuan and few over 1000 yuan. If the price range is evenly divided into 10, the difference in the number of products in each bucket will be very large.</p>
<p>To achieve even distribution, we can initially set a rough dividing line, roughly dividing the data into 3 buckets. <strong>After the distribution is complete, the buckets with more products can be further divided into 3 buckets, until the number of elements in all buckets is roughly equal</strong>.</p>
<p>As shown in the Figure 11-14 , this method essentially creates a recursive tree, aiming to make the leaf node values as even as possible. Of course, you don't have to divide the data into 3 buckets each round; the specific division method can be flexibly chosen based on data characteristics.</p>
<p>As shown in Figure 11-14, this method essentially creates a recursive tree, aiming to make the leaf node values as even as possible. Of course, you don't have to divide the data into 3 buckets each round; the specific division method can be flexibly chosen based on data characteristics.</p>
<p><a class="glightbox" href="../bucket_sort.assets/scatter_in_buckets_recursively.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Recursive division of buckets" class="animation-figure" src="../bucket_sort.assets/scatter_in_buckets_recursively.png" /></a></p>
<p align="center"> Figure 11-14 &nbsp; Recursive division of buckets </p>
<p>If we know the probability distribution of product prices in advance, <strong>we can set the price dividing line for each bucket based on the data probability distribution</strong>. It is worth noting that it is not necessarily required to specifically calculate the data distribution; it can also be approximated based on data characteristics using some probability model.</p>
<p>As shown in the Figure 11-15 , we assume that product prices follow a normal distribution, allowing us to reasonably set the price intervals, thereby evenly distributing the products into the respective buckets.</p>
<p>As shown in Figure 11-15, we assume that product prices follow a normal distribution, allowing us to reasonably set the price intervals, thereby evenly distributing the products into the respective buckets.</p>
<p><a class="glightbox" href="../bucket_sort.assets/scatter_in_buckets_distribution.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Dividing buckets based on probability distribution" class="animation-figure" src="../bucket_sort.assets/scatter_in_buckets_distribution.png" /></a></p>
<p align="center"> Figure 11-15 &nbsp; Dividing buckets based on probability distribution </p>

View File

@ -3611,12 +3611,12 @@
<h1 id="114-insertion-sort">11.4 &nbsp; Insertion sort<a class="headerlink" href="#114-insertion-sort" title="Permanent link">&para;</a></h1>
<p><u>Insertion sort</u> is a simple sorting algorithm that works very much like the process of manually sorting a deck of cards.</p>
<p>Specifically, we select a pivot element from the unsorted interval, compare it with the elements in the sorted interval to its left, and insert the element into the correct position.</p>
<p>The Figure 11-6 shows the process of inserting an element into an array. Assuming the pivot element is <code>base</code>, we need to move all elements between the target index and <code>base</code> one position to the right, then assign <code>base</code> to the target index.</p>
<p>Figure 11-6 shows the process of inserting an element into an array. Assuming the pivot element is <code>base</code>, we need to move all elements between the target index and <code>base</code> one position to the right, then assign <code>base</code> to the target index.</p>
<p><a class="glightbox" href="../insertion_sort.assets/insertion_operation.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Single insertion operation" class="animation-figure" src="../insertion_sort.assets/insertion_operation.png" /></a></p>
<p align="center"> Figure 11-6 &nbsp; Single insertion operation </p>
<h2 id="1141-algorithm-process">11.4.1 &nbsp; Algorithm process<a class="headerlink" href="#1141-algorithm-process" title="Permanent link">&para;</a></h2>
<p>The overall process of insertion sort is shown in the following figure.</p>
<p>The overall process of insertion sort is shown in Figure 11-7.</p>
<ol>
<li>Initially, the first element of the array is sorted.</li>
<li>The second element of the array is taken as <code>base</code>, and after inserting it into the correct position, <strong>the first two elements of the array are sorted</strong>.</li>

View File

@ -3609,7 +3609,7 @@
<!-- Page content -->
<h1 id="116-merge-sort">11.6 &nbsp; Merge sort<a class="headerlink" href="#116-merge-sort" title="Permanent link">&para;</a></h1>
<p><u>Merge sort</u> is a sorting algorithm based on the divide-and-conquer strategy, involving the "divide" and "merge" phases shown in the following figure.</p>
<p><u>Merge sort</u> is a sorting algorithm based on the divide-and-conquer strategy, involving the "divide" and "merge" phases shown in Figure 11-10.</p>
<ol>
<li><strong>Divide phase</strong>: Recursively split the array from the midpoint, transforming the sorting problem of a long array into that of shorter arrays.</li>
<li><strong>Merge phase</strong>: Stop dividing when the length of the sub-array is 1, start merging, and continuously combine two shorter ordered arrays into one longer ordered array until the process is complete.</li>
@ -3618,7 +3618,7 @@
<p align="center"> Figure 11-10 &nbsp; The divide and merge phases of merge sort </p>
<h2 id="1161-algorithm-workflow">11.6.1 &nbsp; Algorithm workflow<a class="headerlink" href="#1161-algorithm-workflow" title="Permanent link">&para;</a></h2>
<p>As shown in the Figure 11-11 , the "divide phase" recursively splits the array from the midpoint into two sub-arrays from top to bottom.</p>
<p>As shown in Figure 11-11, the "divide phase" recursively splits the array from the midpoint into two sub-arrays from top to bottom.</p>
<ol>
<li>Calculate the midpoint <code>mid</code>, recursively divide the left sub-array (interval <code>[left, mid]</code>) and the right sub-array (interval <code>[mid + 1, right]</code>).</li>
<li>Continue with step <code>1.</code> recursively until the sub-array interval length is 1 to stop.</li>

View File

@ -4006,7 +4006,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20partition%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%93%A8%E5%85%B5%E5%88%92%E5%88%86%22%22%22%0A%20%20%20%20%23%20%E4%BB%A5%20nums%5Bleft%5D%20%E4%B8%BA%E5%9F%BA%E5%87%86%E6%95%B0%0A%20%20%20%20i,%20j%20%3D%20left,%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E4%BB%8E%E5%8F%B3%E5%90%91%E5%B7%A6%E6%89%BE%E9%A6%96%E4%B8%AA%E5%B0%8F%E4%BA%8E%E5%9F%BA%E5%87%86%E6%95%B0%E7%9A%84%E5%85%83%E7%B4%A0%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E4%BB%8E%E5%B7%A6%E5%90%91%E5%8F%B3%E6%89%BE%E9%A6%96%E4%B8%AA%E5%A4%A7%E4%BA%8E%E5%9F%BA%E5%87%86%E6%95%B0%E7%9A%84%E5%85%83%E7%B4%A0%0A%20%20%20%20%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E4%BA%A4%E6%8D%A2%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bj%5D%20%3D%20nums%5Bj%5D,%20nums%5Bi%5D%0A%20%20%20%20%23%20%E5%B0%86%E5%9F%BA%E5%87%86%E6%95%B0%E4%BA%A4%E6%8D%A2%E8%87%B3%E4%B8%A4%E5%AD%90%E6%95%B0%E7%BB%84%E7%9A%84%E5%88%86%E7%95%8C%E7%BA%BF%0A%20%20%20%20nums%5Bi%5D,%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D,%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E8%BF%94%E5%9B%9E%E5%9F%BA%E5%87%86%E6%95%B0%E7%9A%84%E7%B4%A2%E5%BC%95%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2,%204,%201,%200,%203,%205%5D%0A%20%20%20%20partition%28nums,%200,%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E5%93%A8%E5%85%B5%E5%88%92%E5%88%86%E5%AE%8C%E6%88%90%E5%90%8E%20nums%20%3D%22,%20nums%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<h2 id="1151-algorithm-process">11.5.1 &nbsp; Algorithm process<a class="headerlink" href="#1151-algorithm-process" title="Permanent link">&para;</a></h2>
<p>The overall process of quick sort is shown in the following figure.</p>
<p>The overall process of quick sort is shown in Figure 11-9.</p>
<ol>
<li>First, perform a "pivot partitioning" on the original array to obtain the unsorted left and right sub-arrays.</li>
<li>Then, recursively perform "pivot partitioning" on both the left and right sub-arrays.</li>

View File

@ -3574,7 +3574,7 @@
<!-- Page content -->
<h1 id="112-selection-sort">11.2 &nbsp; Selection sort<a class="headerlink" href="#112-selection-sort" title="Permanent link">&para;</a></h1>
<p><u>Selection sort</u> works on a very simple principle: it starts a loop where each iteration selects the smallest element from the unsorted interval and moves it to the end of the sorted interval.</p>
<p>Suppose the length of the array is <span class="arithmatex">\(n\)</span>, the algorithm flow of selection sort is as shown below.</p>
<p>Suppose the length of the array is <span class="arithmatex">\(n\)</span>, the algorithm flow of selection sort is as shown in Figure 11-2.</p>
<ol>
<li>Initially, all elements are unsorted, i.e., the unsorted (index) interval is <span class="arithmatex">\([0, n-1]\)</span>.</li>
<li>Select the smallest element in the interval <span class="arithmatex">\([0, n-1]\)</span> and swap it with the element at index <span class="arithmatex">\(0\)</span>. After this, the first element of the array is sorted.</li>
@ -3871,7 +3871,7 @@
<ul>
<li><strong>Time complexity of <span class="arithmatex">\(O(n^2)\)</span>, non-adaptive sort</strong>: There are <span class="arithmatex">\(n - 1\)</span> rounds in the outer loop, with the unsorted interval length starting at <span class="arithmatex">\(n\)</span> in the first round and decreasing to <span class="arithmatex">\(2\)</span> in the last round, i.e., the outer loops contain <span class="arithmatex">\(n\)</span>, <span class="arithmatex">\(n - 1\)</span>, <span class="arithmatex">\(\dots\)</span>, <span class="arithmatex">\(3\)</span>, <span class="arithmatex">\(2\)</span> inner loops respectively, summing up to <span class="arithmatex">\(\frac{(n - 1)(n + 2)}{2}\)</span>.</li>
<li><strong>Space complexity of <span class="arithmatex">\(O(1)\)</span>, in-place sort</strong>: Uses constant extra space with pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span>.</li>
<li><strong>Non-stable sort</strong>: As shown in the Figure 11-3 , an element <code>nums[i]</code> may be swapped to the right of an equal element, causing their relative order to change.</li>
<li><strong>Non-stable sort</strong>: As shown in Figure 11-3, an element <code>nums[i]</code> may be swapped to the right of an equal element, causing their relative order to change.</li>
</ul>
<p><a class="glightbox" href="../selection_sort.assets/selection_sort_instability.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Selection sort instability example" class="animation-figure" src="../selection_sort.assets/selection_sort_instability.png" /></a></p>
<p align="center"> Figure 11-3 &nbsp; Selection sort instability example </p>

View File

@ -3592,7 +3592,7 @@
<!-- Page content -->
<h1 id="111-sorting-algorithms">11.1 &nbsp; Sorting algorithms<a class="headerlink" href="#111-sorting-algorithms" title="Permanent link">&para;</a></h1>
<p><u>Sorting algorithms (sorting algorithm)</u> are used to arrange a set of data in a specific order. Sorting algorithms have a wide range of applications because ordered data can usually be searched, analyzed, and processed more efficiently.</p>
<p>As shown in the following figure, the data types in sorting algorithms can be integers, floating point numbers, characters, or strings, etc. Sorting rules can be set according to needs, such as numerical size, character ASCII order, or custom rules.</p>
<p>As shown in Figure 11-1, the data types in sorting algorithms can be integers, floating point numbers, characters, or strings, etc. Sorting rules can be set according to needs, such as numerical size, character ASCII order, or custom rules.</p>
<p><a class="glightbox" href="../sorting_algorithm.assets/sorting_examples.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Data types and comparator examples" class="animation-figure" src="../sorting_algorithm.assets/sorting_examples.png" /></a></p>
<p align="center"> Figure 11-1 &nbsp; Data types and comparator examples </p>

View File

@ -3601,7 +3601,7 @@
<li>Counting sort is a special case of bucket sort, which sorts by counting the occurrences of each data point. Counting sort is suitable for large datasets with a limited range of data and requires that data can be converted to positive integers.</li>
<li>Radix sort sorts data by sorting digit by digit, requiring data to be represented as fixed-length numbers.</li>
<li>Overall, we hope to find a sorting algorithm that has high efficiency, stability, in-place operation, and positive adaptability. However, like other data structures and algorithms, no sorting algorithm can meet all these conditions simultaneously. In practical applications, we need to choose the appropriate sorting algorithm based on the characteristics of the data.</li>
<li>The following figure compares mainstream sorting algorithms in terms of efficiency, stability, in-place nature, and adaptability.</li>
<li>Figure 11-19 compares mainstream sorting algorithms in terms of efficiency, stability, in-place nature, and adaptability.</li>
</ul>
<p><a class="glightbox" href="../summary.assets/sorting_algorithms_comparison.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Sorting Algorithm Comparison" class="animation-figure" src="../summary.assets/sorting_algorithms_comparison.png" /></a></p>
<p align="center"> Figure 11-19 &nbsp; Sorting Algorithm Comparison </p>

View File

@ -4011,7 +4011,7 @@
<h3 id="1-implementation-based-on-doubly-linked-list">1. &nbsp; Implementation based on doubly linked list<a class="headerlink" href="#1-implementation-based-on-doubly-linked-list" title="Permanent link">&para;</a></h3>
<p>Recall from the previous section that we used a regular singly linked list to implement a queue, as it conveniently allows for deleting from the head (corresponding to the dequeue operation) and adding new elements after the tail (corresponding to the enqueue operation).</p>
<p>For a double-ended queue, both the head and the tail can perform enqueue and dequeue operations. In other words, a double-ended queue needs to implement operations in the opposite direction as well. For this, we use a "doubly linked list" as the underlying data structure of the double-ended queue.</p>
<p>As shown in the Figure 5-8 , we treat the head and tail nodes of the doubly linked list as the front and rear of the double-ended queue, respectively, and implement the functionality to add and remove nodes at both ends.</p>
<p>As shown in Figure 5-8, we treat the head and tail nodes of the doubly linked list as the front and rear of the double-ended queue, respectively, and implement the functionality to add and remove nodes at both ends.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:5"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">LinkedListDeque</label><label for="__tabbed_2_2">pushLast()</label><label for="__tabbed_2_3">pushFirst()</label><label for="__tabbed_2_4">popLast()</label><label for="__tabbed_2_5">popFirst()</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -5892,7 +5892,7 @@
</div>
</div>
<h3 id="2-implementation-based-on-array">2. &nbsp; Implementation based on array<a class="headerlink" href="#2-implementation-based-on-array" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 5-9 , similar to implementing a queue with an array, we can also use a circular array to implement a double-ended queue.</p>
<p>As shown in Figure 5-9, similar to implementing a queue with an array, we can also use a circular array to implement a double-ended queue.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:5"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">ArrayDeque</label><label for="__tabbed_4_2">pushLast()</label><label for="__tabbed_4_3">pushFirst()</label><label for="__tabbed_4_4">popLast()</label><label for="__tabbed_4_5">popFirst()</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -3658,12 +3658,12 @@
<!-- Page content -->
<h1 id="52-queue">5.2 &nbsp; Queue<a class="headerlink" href="#52-queue" title="Permanent link">&para;</a></h1>
<p>"Queue" is a linear data structure that follows the First-In-First-Out (FIFO) rule. As the name suggests, a queue simulates the phenomenon of lining up, where newcomers join the queue at the rear, and the person at the front leaves the queue first.</p>
<p>As shown in the Figure 5-4 , we call the front of the queue the "head" and the back the "tail." The operation of adding elements to the rear of the queue is termed "enqueue," and the operation of removing elements from the front is termed "dequeue."</p>
<p>As shown in Figure 5-4, we call the front of the queue the "head" and the back the "tail." The operation of adding elements to the rear of the queue is termed "enqueue," and the operation of removing elements from the front is termed "dequeue."</p>
<p><a class="glightbox" href="../queue.assets/queue_operations.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Queue's first-in-first-out rule" class="animation-figure" src="../queue.assets/queue_operations.png" /></a></p>
<p align="center"> Figure 5-4 &nbsp; Queue's first-in-first-out rule </p>
<h2 id="521-common-operations-on-queue">5.2.1 &nbsp; Common operations on queue<a class="headerlink" href="#521-common-operations-on-queue" title="Permanent link">&para;</a></h2>
<p>The common operations on a queue are shown in the Table 5-2 . Note that method names may vary across different programming languages. Here, we use the same naming convention as that used for stacks.</p>
<p>The common operations on a queue are shown in Table 5-2. Note that method names may vary across different programming languages. Here, we use the same naming convention as that used for stacks.</p>
<p align="center"> Table 5-2 &nbsp; Efficiency of queue operations </p>
<div class="center-table">
@ -3975,7 +3975,7 @@
<h2 id="522-implementing-a-queue">5.2.2 &nbsp; Implementing a queue<a class="headerlink" href="#522-implementing-a-queue" title="Permanent link">&para;</a></h2>
<p>To implement a queue, we need a data structure that allows adding elements at one end and removing them at the other. Both linked lists and arrays meet this requirement.</p>
<h3 id="1-implementation-based-on-a-linked-list">1. &nbsp; Implementation based on a linked list<a class="headerlink" href="#1-implementation-based-on-a-linked-list" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 5-5 , we can consider the "head node" and "tail node" of a linked list as the "front" and "rear" of the queue, respectively. It is stipulated that nodes can only be added at the rear and removed at the front.</p>
<p>As shown in Figure 5-5, we can consider the "head node" and "tail node" of a linked list as the "front" and "rear" of the queue, respectively. It is stipulated that nodes can only be added at the rear and removed at the front.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:3"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">LinkedListQueue</label><label for="__tabbed_2_2">push()</label><label for="__tabbed_2_3">pop()</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -4978,7 +4978,7 @@
<h3 id="2-implementation-based-on-an-array">2. &nbsp; Implementation based on an array<a class="headerlink" href="#2-implementation-based-on-an-array" title="Permanent link">&para;</a></h3>
<p>Deleting the first element in an array has a time complexity of <span class="arithmatex">\(O(n)\)</span>, which would make the dequeue operation inefficient. However, this problem can be cleverly avoided as follows.</p>
<p>We use a variable <code>front</code> to indicate the index of the front element and maintain a variable <code>size</code> to record the queue's length. Define <code>rear = front + size</code>, which points to the position immediately following the tail element.</p>
<p>With this design, <strong>the effective interval of elements in the array is <code>[front, rear - 1]</code></strong>. The implementation methods for various operations are shown in the Figure 5-6 .</p>
<p>With this design, <strong>the effective interval of elements in the array is <code>[front, rear - 1]</code></strong>. The implementation methods for various operations are shown in Figure 5-6.</p>
<ul>
<li>Enqueue operation: Assign the input element to the <code>rear</code> index and increase <code>size</code> by 1.</li>
<li>Dequeue operation: Simply increase <code>front</code> by 1 and decrease <code>size</code> by 1.</li>

View File

@ -3677,12 +3677,12 @@
<h1 id="51-stack">5.1 &nbsp; Stack<a class="headerlink" href="#51-stack" title="Permanent link">&para;</a></h1>
<p>A "Stack" is a linear data structure that follows the principle of Last-In-First-Out (LIFO).</p>
<p>We can compare a stack to a pile of plates on a table. To access the bottom plate, one must first remove the plates on top. By replacing the plates with various types of elements (such as integers, characters, objects, etc.), we obtain the data structure known as a stack.</p>
<p>As shown in the Figure 5-1 , we refer to the top of the pile of elements as the "top of the stack" and the bottom as the "bottom of the stack." The operation of adding elements to the top of the stack is called "push," and the operation of removing the top element is called "pop."</p>
<p>As shown in Figure 5-1, we refer to the top of the pile of elements as the "top of the stack" and the bottom as the "bottom of the stack." The operation of adding elements to the top of the stack is called "push," and the operation of removing the top element is called "pop."</p>
<p><a class="glightbox" href="../stack.assets/stack_operations.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Stack's last-in-first-out rule" class="animation-figure" src="../stack.assets/stack_operations.png" /></a></p>
<p align="center"> Figure 5-1 &nbsp; Stack's last-in-first-out rule </p>
<h2 id="511-common-operations-on-stack">5.1.1 &nbsp; Common operations on stack<a class="headerlink" href="#511-common-operations-on-stack" title="Permanent link">&para;</a></h2>
<p>The common operations on a stack are shown in the Table 5-1 . The specific method names depend on the programming language used. Here, we use <code>push()</code>, <code>pop()</code>, and <code>peek()</code> as examples.</p>
<p>The common operations on a stack are shown in Table 5-1. The specific method names depend on the programming language used. Here, we use <code>push()</code>, <code>pop()</code>, and <code>peek()</code> as examples.</p>
<p align="center"> Table 5-1 &nbsp; Efficiency of stack operations </p>
<div class="center-table">
@ -3988,7 +3988,7 @@
<p>A stack follows the principle of Last-In-First-Out, which means we can only add or remove elements at the top of the stack. However, both arrays and linked lists allow adding and removing elements at any position, <strong>therefore a stack can be seen as a restricted array or linked list</strong>. In other words, we can "shield" certain irrelevant operations of an array or linked list, aligning their external behavior with the characteristics of a stack.</p>
<h3 id="1-implementation-based-on-a-linked-list">1. &nbsp; Implementation based on a linked list<a class="headerlink" href="#1-implementation-based-on-a-linked-list" title="Permanent link">&para;</a></h3>
<p>When implementing a stack using a linked list, we can consider the head node of the list as the top of the stack and the tail node as the bottom of the stack.</p>
<p>As shown in the Figure 5-2 , for the push operation, we simply insert elements at the head of the linked list. This method of node insertion is known as "head insertion." For the pop operation, we just need to remove the head node from the list.</p>
<p>As shown in Figure 5-2, for the push operation, we simply insert elements at the head of the linked list. This method of node insertion is known as "head insertion." For the pop operation, we just need to remove the head node from the list.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:3"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">LinkedListStack</label><label for="__tabbed_2_2">push()</label><label for="__tabbed_2_3">pop()</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -4838,7 +4838,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%93%BE%E8%A1%A8%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%90%8E%E7%BB%A7%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%0Aclass%20LinkedListStack%3A%0A%20%20%20%20%22%22%22%E5%9F%BA%E4%BA%8E%E9%93%BE%E8%A1%A8%E5%AE%9E%E7%8E%B0%E7%9A%84%E6%A0%88%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%22%22%22%0A%20%20%20%20%20%20%20%20self._peek%3A%20ListNode%20%7C%20None%20%3D%20None%0A%20%20%20%20%20%20%20%20self._size%3A%20int%20%3D%200%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%8E%B7%E5%8F%96%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._size%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%88%A4%E6%96%AD%E6%A0%88%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%22%22%22%0A%20%20%20%20%20%20%20%20return%20not%20self._peek%0A%0A%20%20%20%20def%20push%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%85%A5%E6%A0%88%22%22%22%0A%20%20%20%20%20%20%20%20node%20%3D%20ListNode%28val%29%0A%20%20%20%20%20%20%20%20node.next%20%3D%20self._peek%0A%20%20%20%20%20%20%20%20self._peek%20%3D%20node%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%87%BA%E6%A0%88%22%22%22%0A%20%20%20%20%20%20%20%20num%20%3D%20self.peek%28%29%0A%20%20%20%20%20%20%20%20self._peek%20%3D%20self._peek.next%0A%20%20%20%20%20%20%20%20self._size%20-%3D%201%0A%20%20%20%20%20%20%20%20return%20num%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%AE%BF%E9%97%AE%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E6%A0%88%E4%B8%BA%E7%A9%BA%22%29%0A%20%20%20%20%20%20%20%20return%20self._peek.val%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%BD%AC%E5%8C%96%E4%B8%BA%E5%88%97%E8%A1%A8%E7%94%A8%E4%BA%8E%E6%89%93%E5%8D%B0%22%22%22%0A%20%20%20%20%20%20%20%20arr%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20node%20%3D%20self._peek%0A%20%20%20%20%20%20%20%20while%20node%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20arr.append%28node.val%29%0A%20%20%20%20%20%20%20%20%20%20%20%20node%20%3D%20node.next%0A%20%20%20%20%20%20%20%20arr.reverse%28%29%0A%20%20%20%20%20%20%20%20return%20arr%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%A0%88%0A%20%20%20%20stack%20%3D%20LinkedListStack%28%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E6%A0%88%0A%20%20%20%20stack.push%281%29%0A%20%20%20%20stack.push%283%29%0A%20%20%20%20stack.push%282%29%0A%20%20%20%20stack.push%285%29%0A%20%20%20%20stack.push%284%29%0A%20%20%20%20print%28%22%E6%A0%88%20stack%20%3D%22,%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%0A%20%20%20%20peek%20%3D%20stack.peek%28%29%0A%20%20%20%20print%28%22%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%20peek%20%3D%22,%20peek%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E6%A0%88%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E5%87%BA%E6%A0%88%E5%85%83%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%20%20%20%20print%28%22%E5%87%BA%E6%A0%88%E5%90%8E%20stack%20%3D%22,%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20stack.size%28%29%0A%20%20%20%20print%28%22%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20stack.is_empty%28%29%0A%20%20%20%20print%28%22%E6%A0%88%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=4&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<h3 id="2-implementation-based-on-an-array">2. &nbsp; Implementation based on an array<a class="headerlink" href="#2-implementation-based-on-an-array" title="Permanent link">&para;</a></h3>
<p>When implementing a stack using an array, we can consider the end of the array as the top of the stack. As shown in the Figure 5-3 , push and pop operations correspond to adding and removing elements at the end of the array, respectively, both with a time complexity of <span class="arithmatex">\(O(1)\)</span>.</p>
<p>When implementing a stack using an array, we can consider the end of the array as the top of the stack. As shown in Figure 5-3, push and pop operations correspond to adding and removing elements at the end of the array, respectively, both with a time complexity of <span class="arithmatex">\(O(1)\)</span>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:3"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">ArrayStack</label><label for="__tabbed_4_2">push()</label><label for="__tabbed_4_3">pop()</label></div>
<div class="tabbed-content">
<div class="tabbed-block">

View File

@ -3613,18 +3613,18 @@
<p>So, can we use an array to represent a binary tree? The answer is yes.</p>
<h2 id="731-representing-perfect-binary-trees">7.3.1 &nbsp; Representing perfect binary trees<a class="headerlink" href="#731-representing-perfect-binary-trees" title="Permanent link">&para;</a></h2>
<p>Let's analyze a simple case first. Given a perfect binary tree, we store all nodes in an array according to the order of level-order traversal, where each node corresponds to a unique array index.</p>
<p>Based on the characteristics of level-order traversal, we can deduce a "mapping formula" between the index of a parent node and its children: <strong>If a node's index is <span class="arithmatex">\(i\)</span>, then the index of its left child is <span class="arithmatex">\(2i + 1\)</span> and the right child is <span class="arithmatex">\(2i + 2\)</span></strong>. The Figure 7-12 shows the mapping relationship between the indices of various nodes.</p>
<p>Based on the characteristics of level-order traversal, we can deduce a "mapping formula" between the index of a parent node and its children: <strong>If a node's index is <span class="arithmatex">\(i\)</span>, then the index of its left child is <span class="arithmatex">\(2i + 1\)</span> and the right child is <span class="arithmatex">\(2i + 2\)</span></strong>. Figure 7-12 shows the mapping relationship between the indices of various nodes.</p>
<p><a class="glightbox" href="../array_representation_of_tree.assets/array_representation_binary_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Array representation of a perfect binary tree" class="animation-figure" src="../array_representation_of_tree.assets/array_representation_binary_tree.png" /></a></p>
<p align="center"> Figure 7-12 &nbsp; Array representation of a perfect binary tree </p>
<p><strong>The mapping formula plays a role similar to the node references (pointers) in linked lists</strong>. Given any node in the array, we can access its left (right) child node using the mapping formula.</p>
<h2 id="732-representing-any-binary-tree">7.3.2 &nbsp; Representing any binary tree<a class="headerlink" href="#732-representing-any-binary-tree" title="Permanent link">&para;</a></h2>
<p>Perfect binary trees are a special case; there are often many <code>None</code> values in the middle levels of a binary tree. Since the sequence of level-order traversal does not include these <code>None</code> values, we cannot solely rely on this sequence to deduce the number and distribution of <code>None</code> values. <strong>This means that multiple binary tree structures can match the same level-order traversal sequence</strong>.</p>
<p>As shown in the Figure 7-13 , given a non-perfect binary tree, the above method of array representation fails.</p>
<p>As shown in Figure 7-13, given a non-perfect binary tree, the above method of array representation fails.</p>
<p><a class="glightbox" href="../array_representation_of_tree.assets/array_representation_without_empty.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Level-order traversal sequence corresponds to multiple binary tree possibilities" class="animation-figure" src="../array_representation_of_tree.assets/array_representation_without_empty.png" /></a></p>
<p align="center"> Figure 7-13 &nbsp; Level-order traversal sequence corresponds to multiple binary tree possibilities </p>
<p>To solve this problem, <strong>we can consider explicitly writing out all <code>None</code> values in the level-order traversal sequence</strong>. As shown in the following figure, after this treatment, the level-order traversal sequence can uniquely represent a binary tree. Example code is as follows:</p>
<p>To solve this problem, <strong>we can consider explicitly writing out all <code>None</code> values in the level-order traversal sequence</strong>. As shown in Figure 7-14, after this treatment, the level-order traversal sequence can uniquely represent a binary tree. Example code is as follows:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:14"><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" /><input id="__tabbed_1_13" name="__tabbed_1" type="radio" /><input id="__tabbed_1_14" 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">Kotlin</label><label for="__tabbed_1_13">Ruby</label><label for="__tabbed_1_14">Zig</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -3713,7 +3713,7 @@
<p align="center"> Figure 7-14 &nbsp; Array representation of any type of binary tree </p>
<p>It's worth noting that <strong>complete binary trees are very suitable for array representation</strong>. Recalling the definition of a complete binary tree, <code>None</code> appears only at the bottom level and towards the right, <strong>meaning all <code>None</code> values definitely appear at the end of the level-order traversal sequence</strong>.</p>
<p>This means that when using an array to represent a complete binary tree, it's possible to omit storing all <code>None</code> values, which is very convenient. The Figure 7-15 gives an example.</p>
<p>This means that when using an array to represent a complete binary tree, it's possible to omit storing all <code>None</code> values, which is very convenient. Figure 7-15 gives an example.</p>
<p><a class="glightbox" href="../array_representation_of_tree.assets/array_representation_complete_binary_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Array representation of a complete binary tree" class="animation-figure" src="../array_representation_of_tree.assets/array_representation_complete_binary_tree.png" /></a></p>
<p align="center"> Figure 7-15 &nbsp; Array representation of a complete binary tree </p>

View File

@ -3844,11 +3844,11 @@
<!-- Page content -->
<h1 id="75-avl-tree">7.5 &nbsp; AVL tree *<a class="headerlink" href="#75-avl-tree" title="Permanent link">&para;</a></h1>
<p>In the "Binary Search Tree" section, we mentioned that after multiple insertions and removals, a binary search tree might degrade to a linked list. In such cases, the time complexity of all operations degrades from <span class="arithmatex">\(O(\log n)\)</span> to <span class="arithmatex">\(O(n)\)</span>.</p>
<p>As shown in the Figure 7-24 , after two node removal operations, this binary search tree will degrade into a linked list.</p>
<p>As shown in Figure 7-24, after two node removal operations, this binary search tree will degrade into a linked list.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_degradation_from_removing_node.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Degradation of an AVL tree after removing nodes" class="animation-figure" src="../avl_tree.assets/avltree_degradation_from_removing_node.png" /></a></p>
<p align="center"> Figure 7-24 &nbsp; Degradation of an AVL tree after removing nodes </p>
<p>For example, in the perfect binary tree shown in the Figure 7-25 , after inserting two nodes, the tree will lean heavily to the left, and the time complexity of search operations will also degrade.</p>
<p>For example, in the perfect binary tree shown in Figure 7-25, after inserting two nodes, the tree will lean heavily to the left, and the time complexity of search operations will also degrade.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_degradation_from_inserting_node.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Degradation of an AVL tree after inserting nodes" class="animation-figure" src="../avl_tree.assets/avltree_degradation_from_inserting_node.png" /></a></p>
<p align="center"> Figure 7-25 &nbsp; Degradation of an AVL tree after inserting nodes </p>
@ -4432,7 +4432,7 @@
<p>The characteristic feature of an AVL tree is the "rotation" operation, which can restore balance to an unbalanced node without affecting the in-order traversal sequence of the binary tree. In other words, <strong>the rotation operation can maintain the property of a "binary search tree" while also turning the tree back into a "balanced binary tree"</strong>.</p>
<p>We call nodes with an absolute balance factor <span class="arithmatex">\(&gt; 1\)</span> "unbalanced nodes". Depending on the type of imbalance, there are four kinds of rotations: right rotation, left rotation, right-left rotation, and left-right rotation. Below, we detail these rotation operations.</p>
<h3 id="1-right-rotation">1. &nbsp; Right rotation<a class="headerlink" href="#1-right-rotation" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 7-26 , the first unbalanced node from the bottom up in the binary tree is "node 3". Focusing on the subtree with this unbalanced node as the root, denoted as <code>node</code>, and its left child as <code>child</code>, perform a "right rotation". After the right rotation, the subtree is balanced again while still maintaining the properties of a binary search tree.</p>
<p>As shown in Figure 7-26, the first unbalanced node from the bottom up in the binary tree is "node 3". Focusing on the subtree with this unbalanced node as the root, denoted as <code>node</code>, and its left child as <code>child</code>, perform a "right rotation". After the right rotation, the subtree is balanced again while still maintaining the properties of a binary search tree.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:4"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">&lt;1&gt;</label><label for="__tabbed_4_2">&lt;2&gt;</label><label for="__tabbed_4_3">&lt;3&gt;</label><label for="__tabbed_4_4">&lt;4&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@ -4451,7 +4451,7 @@
</div>
<p align="center"> Figure 7-26 &nbsp; Steps of right rotation </p>
<p>As shown in the Figure 7-27 , when the <code>child</code> node has a right child (denoted as <code>grand_child</code>), a step needs to be added in the right rotation: set <code>grand_child</code> as the left child of <code>node</code>.</p>
<p>As shown in Figure 7-27, when the <code>child</code> node has a right child (denoted as <code>grand_child</code>), a step needs to be added in the right rotation: set <code>grand_child</code> as the left child of <code>node</code>.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_right_rotate_with_grandchild.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Right rotation with grand_child" class="animation-figure" src="../avl_tree.assets/avltree_right_rotate_with_grandchild.png" /></a></p>
<p align="center"> Figure 7-27 &nbsp; Right rotation with grand_child </p>
@ -4690,11 +4690,11 @@
</div>
</div>
<h3 id="2-left-rotation">2. &nbsp; Left rotation<a class="headerlink" href="#2-left-rotation" title="Permanent link">&para;</a></h3>
<p>Correspondingly, if considering the "mirror" of the above unbalanced binary tree, the "left rotation" operation shown in the Figure 7-28 needs to be performed.</p>
<p>Correspondingly, if considering the "mirror" of the above unbalanced binary tree, the "left rotation" operation shown in Figure 7-28 needs to be performed.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_left_rotate.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Left rotation operation" class="animation-figure" src="../avl_tree.assets/avltree_left_rotate.png" /></a></p>
<p align="center"> Figure 7-28 &nbsp; Left rotation operation </p>
<p>Similarly, as shown in the Figure 7-29 , when the <code>child</code> node has a left child (denoted as <code>grand_child</code>), a step needs to be added in the left rotation: set <code>grand_child</code> as the right child of <code>node</code>.</p>
<p>Similarly, as shown in Figure 7-29, when the <code>child</code> node has a left child (denoted as <code>grand_child</code>), a step needs to be added in the left rotation: set <code>grand_child</code> as the right child of <code>node</code>.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_left_rotate_with_grandchild.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Left rotation with grand_child" class="animation-figure" src="../avl_tree.assets/avltree_left_rotate_with_grandchild.png" /></a></p>
<p align="center"> Figure 7-29 &nbsp; Left rotation with grand_child </p>
@ -4933,21 +4933,21 @@
</div>
</div>
<h3 id="3-right-left-rotation">3. &nbsp; Right-left rotation<a class="headerlink" href="#3-right-left-rotation" title="Permanent link">&para;</a></h3>
<p>For the unbalanced node 3 shown in the Figure 7-30 , using either left or right rotation alone cannot restore balance to the subtree. In this case, a "left rotation" needs to be performed on <code>child</code> first, followed by a "right rotation" on <code>node</code>.</p>
<p>For the unbalanced node 3 shown in Figure 7-30, using either left or right rotation alone cannot restore balance to the subtree. In this case, a "left rotation" needs to be performed on <code>child</code> first, followed by a "right rotation" on <code>node</code>.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_left_right_rotate.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Right-left rotation" class="animation-figure" src="../avl_tree.assets/avltree_left_right_rotate.png" /></a></p>
<p align="center"> Figure 7-30 &nbsp; Right-left rotation </p>
<h3 id="4-left-right-rotation">4. &nbsp; Left-right rotation<a class="headerlink" href="#4-left-right-rotation" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 7-31 , for the mirror case of the above unbalanced binary tree, a "right rotation" needs to be performed on <code>child</code> first, followed by a "left rotation" on <code>node</code>.</p>
<p>As shown in Figure 7-31, for the mirror case of the above unbalanced binary tree, a "right rotation" needs to be performed on <code>child</code> first, followed by a "left rotation" on <code>node</code>.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_right_left_rotate.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Left-right rotation" class="animation-figure" src="../avl_tree.assets/avltree_right_left_rotate.png" /></a></p>
<p align="center"> Figure 7-31 &nbsp; Left-right rotation </p>
<h3 id="5-choice-of-rotation">5. &nbsp; Choice of rotation<a class="headerlink" href="#5-choice-of-rotation" title="Permanent link">&para;</a></h3>
<p>The four kinds of imbalances shown in the Figure 7-32 correspond to the cases described above, respectively requiring right rotation, left-right rotation, right-left rotation, and left rotation.</p>
<p>The four kinds of imbalances shown in Figure 7-32 correspond to the cases described above, respectively requiring right rotation, left-right rotation, right-left rotation, and left rotation.</p>
<p><a class="glightbox" href="../avl_tree.assets/avltree_rotation_cases.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="The four rotation cases of AVL tree" class="animation-figure" src="../avl_tree.assets/avltree_rotation_cases.png" /></a></p>
<p align="center"> Figure 7-32 &nbsp; The four rotation cases of AVL tree </p>
<p>As shown in the Table 7-3 , we determine which of the above cases an unbalanced node belongs to by judging the sign of the balance factor of the unbalanced node and its higher-side child's balance factor.</p>
<p>As shown in Table 7-3, we determine which of the above cases an unbalanced node belongs to by judging the sign of the balance factor of the unbalanced node and its higher-side child's balance factor.</p>
<p align="center"> Table 7-3 &nbsp; Conditions for Choosing Among the Four Rotation Cases </p>
<div class="center-table">

File diff suppressed because one or more lines are too long

View File

@ -3933,12 +3933,12 @@
</div>
</div>
<p>Each node has two references (pointers), pointing to the "left-child node" and "right-child node," respectively. This node is called the "parent node" of these two child nodes. When given a node of a binary tree, we call the tree formed by this node's left child and all nodes under it the "left subtree" of this node. Similarly, the "right subtree" can be defined.</p>
<p><strong>In a binary tree, except for leaf nodes, all other nodes contain child nodes and non-empty subtrees.</strong> As shown in the Figure 7-1 , if "Node 2" is considered as the parent node, then its left and right child nodes are "Node 4" and "Node 5," respectively. The left subtree is "the tree formed by Node 4 and all nodes under it," and the right subtree is "the tree formed by Node 5 and all nodes under it."</p>
<p><strong>In a binary tree, except for leaf nodes, all other nodes contain child nodes and non-empty subtrees.</strong> As shown in Figure 7-1, if "Node 2" is considered as the parent node, then its left and right child nodes are "Node 4" and "Node 5," respectively. The left subtree is "the tree formed by Node 4 and all nodes under it," and the right subtree is "the tree formed by Node 5 and all nodes under it."</p>
<p><a class="glightbox" href="../binary_tree.assets/binary_tree_definition.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Parent Node, child Node, subtree" class="animation-figure" src="../binary_tree.assets/binary_tree_definition.png" /></a></p>
<p align="center"> Figure 7-1 &nbsp; Parent Node, child Node, subtree </p>
<h2 id="711-common-terminology-of-binary-trees">7.1.1 &nbsp; Common terminology of binary trees<a class="headerlink" href="#711-common-terminology-of-binary-trees" title="Permanent link">&para;</a></h2>
<p>The commonly used terminology of binary trees is shown in the following figure.</p>
<p>The commonly used terminology of binary trees is shown in Figure 7-2.</p>
<ul>
<li>"Root node": The node at the top level of the binary tree, which has no parent node.</li>
<li>"Leaf node": A node with no children, both of its pointers point to <code>None</code>.</li>
@ -4152,7 +4152,7 @@
<p>https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%8F%89%E6%A0%91%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BA%8C%E5%8F%89%E6%A0%91%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E8%8A%82%E7%82%B9%0A%20%20%20%20n1%20%3D%20TreeNode%28val%3D1%29%0A%20%20%20%20n2%20%3D%20TreeNode%28val%3D2%29%0A%20%20%20%20n3%20%3D%20TreeNode%28val%3D3%29%0A%20%20%20%20n4%20%3D%20TreeNode%28val%3D4%29%0A%20%20%20%20n5%20%3D%20TreeNode%28val%3D5%29%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E7%9A%84%E5%BC%95%E7%94%A8%EF%BC%88%E6%8C%87%E9%92%88%EF%BC%89%0A%20%20%20%20n1.left%20%3D%20n2%0A%20%20%20%20n1.right%20%3D%20n3%0A%20%20%20%20n2.left%20%3D%20n4%0A%20%20%20%20n2.right%20%3D%20n5&amp;cumulative=false&amp;curInstr=3&amp;heapPrimitives=nevernest&amp;mode=display&amp;origin=opt-frontend.js&amp;py=311&amp;rawInputLstJSON=%5B%5D&amp;textReferences=false</p>
</details>
<h3 id="2-inserting-and-removing-nodes">2. &nbsp; Inserting and removing nodes<a class="headerlink" href="#2-inserting-and-removing-nodes" title="Permanent link">&para;</a></h3>
<p>Similar to a linked list, inserting and removing nodes in a binary tree can be achieved by modifying pointers. The Figure 7-3 provides an example.</p>
<p>Similar to a linked list, inserting and removing nodes in a binary tree can be achieved by modifying pointers. Figure 7-3 provides an example.</p>
<p><a class="glightbox" href="../binary_tree.assets/binary_tree_add_remove.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Inserting and removing nodes in a binary tree" class="animation-figure" src="../binary_tree.assets/binary_tree_add_remove.png" /></a></p>
<p align="center"> Figure 7-3 &nbsp; Inserting and removing nodes in a binary tree </p>
@ -4294,7 +4294,7 @@
</div>
<h2 id="713-common-types-of-binary-trees">7.1.3 &nbsp; Common types of binary trees<a class="headerlink" href="#713-common-types-of-binary-trees" title="Permanent link">&para;</a></h2>
<h3 id="1-perfect-binary-tree">1. &nbsp; Perfect binary tree<a class="headerlink" href="#1-perfect-binary-tree" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 7-4 , in a "perfect binary tree," all levels of nodes are fully filled. In a perfect binary tree, the degree of leaf nodes is <span class="arithmatex">\(0\)</span>, and the degree of all other nodes is <span class="arithmatex">\(2\)</span>; if the tree's height is <span class="arithmatex">\(h\)</span>, then the total number of nodes is <span class="arithmatex">\(2^{h+1} - 1\)</span>, showing a standard exponential relationship, reflecting the common phenomenon of cell division in nature.</p>
<p>As shown in Figure 7-4, in a "perfect binary tree," all levels of nodes are fully filled. In a perfect binary tree, the degree of leaf nodes is <span class="arithmatex">\(0\)</span>, and the degree of all other nodes is <span class="arithmatex">\(2\)</span>; if the tree's height is <span class="arithmatex">\(h\)</span>, then the total number of nodes is <span class="arithmatex">\(2^{h+1} - 1\)</span>, showing a standard exponential relationship, reflecting the common phenomenon of cell division in nature.</p>
<div class="admonition tip">
<p class="admonition-title">Tip</p>
<p>Please note that in the Chinese community, a perfect binary tree is often referred to as a "full binary tree."</p>
@ -4303,22 +4303,22 @@
<p align="center"> Figure 7-4 &nbsp; Perfect binary tree </p>
<h3 id="2-complete-binary-tree">2. &nbsp; Complete binary tree<a class="headerlink" href="#2-complete-binary-tree" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 7-5 , a "complete binary tree" has only the bottom level nodes not fully filled, and the bottom level nodes are filled as far left as possible.</p>
<p>As shown in Figure 7-5, a "complete binary tree" has only the bottom level nodes not fully filled, and the bottom level nodes are filled as far left as possible.</p>
<p><a class="glightbox" href="../binary_tree.assets/complete_binary_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Complete binary tree" class="animation-figure" src="../binary_tree.assets/complete_binary_tree.png" /></a></p>
<p align="center"> Figure 7-5 &nbsp; Complete binary tree </p>
<h3 id="3-full-binary-tree">3. &nbsp; Full binary tree<a class="headerlink" href="#3-full-binary-tree" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 7-6 , a "full binary tree" has all nodes except leaf nodes having two children.</p>
<p>As shown in Figure 7-6, a "full binary tree" has all nodes except leaf nodes having two children.</p>
<p><a class="glightbox" href="../binary_tree.assets/full_binary_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Full binary tree" class="animation-figure" src="../binary_tree.assets/full_binary_tree.png" /></a></p>
<p align="center"> Figure 7-6 &nbsp; Full binary tree </p>
<h3 id="4-balanced-binary-tree">4. &nbsp; Balanced binary tree<a class="headerlink" href="#4-balanced-binary-tree" title="Permanent link">&para;</a></h3>
<p>As shown in the Figure 7-7 , in a "balanced binary tree," the absolute difference in height between the left and right subtrees of any node does not exceed 1.</p>
<p>As shown in Figure 7-7, in a "balanced binary tree," the absolute difference in height between the left and right subtrees of any node does not exceed 1.</p>
<p><a class="glightbox" href="../binary_tree.assets/balanced_binary_tree.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Balanced binary tree" class="animation-figure" src="../binary_tree.assets/balanced_binary_tree.png" /></a></p>
<p align="center"> Figure 7-7 &nbsp; Balanced binary tree </p>
<h2 id="714-degeneration-of-binary-trees">7.1.4 &nbsp; Degeneration of binary trees<a class="headerlink" href="#714-degeneration-of-binary-trees" title="Permanent link">&para;</a></h2>
<p>The Figure 7-8 shows the ideal and degenerate structures of binary trees. When every level of a binary tree is filled, it reaches the "perfect binary tree"; when all nodes are biased towards one side, the binary tree degenerates into a "linked list".</p>
<p>Figure 7-8 shows the ideal and degenerate structures of binary trees. When every level of a binary tree is filled, it reaches the "perfect binary tree"; when all nodes are biased towards one side, the binary tree degenerates into a "linked list".</p>
<ul>
<li>The perfect binary tree is the ideal situation, fully leveraging the "divide and conquer" advantage of binary trees.</li>
<li>A linked list is another extreme, where operations become linear, degrading the time complexity to <span class="arithmatex">\(O(n)\)</span>.</li>
@ -4326,7 +4326,7 @@
<p><a class="glightbox" href="../binary_tree.assets/binary_tree_best_worst_cases.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="The Best and Worst Structures of Binary Trees" class="animation-figure" src="../binary_tree.assets/binary_tree_best_worst_cases.png" /></a></p>
<p align="center"> Figure 7-8 &nbsp; The Best and Worst Structures of Binary Trees </p>
<p>As shown in the Table 7-1 , in the best and worst structures, the number of leaf nodes, total number of nodes, and height of the binary tree reach their maximum or minimum values.</p>
<p>As shown in Table 7-1, in the best and worst structures, the number of leaf nodes, total number of nodes, and height of the binary tree reach their maximum or minimum values.</p>
<p align="center"> Table 7-1 &nbsp; The Best and Worst Structures of Binary Trees </p>
<div class="center-table">

View File

@ -3690,7 +3690,7 @@
<p>From the perspective of physical structure, a tree is a data structure based on linked lists, hence its traversal method involves accessing nodes one by one through pointers. However, a tree is a non-linear data structure, which makes traversing a tree more complex than traversing a linked list, requiring the assistance of search algorithms to achieve.</p>
<p>Common traversal methods for binary trees include level-order traversal, preorder traversal, inorder traversal, and postorder traversal, among others.</p>
<h2 id="721-level-order-traversal">7.2.1 &nbsp; Level-order traversal<a class="headerlink" href="#721-level-order-traversal" title="Permanent link">&para;</a></h2>
<p>As shown in the Figure 7-9 , "level-order traversal" traverses the binary tree from top to bottom, layer by layer, and accesses nodes in each layer in a left-to-right order.</p>
<p>As shown in Figure 7-9, "level-order traversal" traverses the binary tree from top to bottom, layer by layer, and accesses nodes in each layer in a left-to-right order.</p>
<p>Level-order traversal essentially belongs to "breadth-first traversal", also known as "breadth-first search (BFS)", which embodies a "circumferentially outward expanding" layer-by-layer traversal method.</p>
<p><a class="glightbox" href="../binary_tree_traversal.assets/binary_tree_bfs.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Level-order traversal of a binary tree" class="animation-figure" src="../binary_tree_traversal.assets/binary_tree_bfs.png" /></a></p>
<p align="center"> Figure 7-9 &nbsp; Level-order traversal of a binary tree </p>
@ -4029,7 +4029,7 @@
</ul>
<h2 id="722-preorder-inorder-and-postorder-traversal">7.2.2 &nbsp; Preorder, inorder, and postorder traversal<a class="headerlink" href="#722-preorder-inorder-and-postorder-traversal" title="Permanent link">&para;</a></h2>
<p>Correspondingly, preorder, inorder, and postorder traversal all belong to "depth-first traversal", also known as "depth-first search (DFS)", which embodies a "proceed to the end first, then backtrack and continue" traversal method.</p>
<p>The Figure 7-10 shows the working principle of performing a depth-first traversal on a binary tree. <strong>Depth-first traversal is like walking around the perimeter of the entire binary tree</strong>, encountering three positions at each node, corresponding to preorder traversal, inorder traversal, and postorder traversal.</p>
<p>Figure 7-10 shows the working principle of performing a depth-first traversal on a binary tree. <strong>Depth-first traversal is like walking around the perimeter of the entire binary tree</strong>, encountering three positions at each node, corresponding to preorder traversal, inorder traversal, and postorder traversal.</p>
<p><a class="glightbox" href="../binary_tree_traversal.assets/binary_tree_dfs.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Preorder, inorder, and postorder traversal of a binary search tree" class="animation-figure" src="../binary_tree_traversal.assets/binary_tree_dfs.png" /></a></p>
<p align="center"> Figure 7-10 &nbsp; Preorder, inorder, and postorder traversal of a binary search tree </p>
@ -4496,7 +4496,7 @@
<p class="admonition-title">Tip</p>
<p>Depth-first search can also be implemented based on iteration, interested readers can study this on their own.</p>
</div>
<p>The Figure 7-11 shows the recursive process of preorder traversal of a binary tree, which can be divided into two opposite parts: "recursion" and "return".</p>
<p>Figure 7-11 shows the recursive process of preorder traversal of a binary tree, which can be divided into two opposite parts: "recursion" and "return".</p>
<ol>
<li>"Recursion" means starting a new method, the program accesses the next node in this process.</li>
<li>"Return" means the function returns, indicating the current node has been fully accessed.</li>

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.