This commit is contained in:
krahets
2025-12-31 19:38:45 +08:00
parent fdc032e300
commit f31cbc3f9f
474 changed files with 130810 additions and 103691 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -37,7 +37,7 @@
<title>12.1 Divide and conquer algorithms - Hello Algo</title>
<title>12.1 Divide and Conquer Algorithms - Hello Algo</title>
@@ -58,8 +58,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Lato";--md-code-font:"JetBrains Mono"}</style>
@@ -154,7 +154,7 @@
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
</span>
</div>
@@ -371,7 +371,7 @@
<span class="md-ellipsis">
Before starting
Before Starting
@@ -388,7 +388,7 @@
<span class="md-nav__icon md-icon"></span>
Before starting
Before Starting
</label>
@@ -487,7 +487,7 @@
<span class="md-ellipsis">
0.1 About this book
0.1 About This Book
@@ -515,7 +515,7 @@
<span class="md-ellipsis">
0.2 How to read
0.2 How to Use This Book
@@ -604,7 +604,7 @@
<span class="md-ellipsis">
Chapter 1. Encounter with algorithms
Chapter 1. Encounter With Algorithms
@@ -626,7 +626,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 1. Encounter with algorithms
Chapter 1. Encounter With Algorithms
</label>
@@ -648,7 +648,7 @@
<span class="md-ellipsis">
1.1 Algorithms are everywhere
1.1 Algorithms Are Everywhere
@@ -676,7 +676,7 @@
<span class="md-ellipsis">
1.2 What is an algorithm
1.2 What Is an Algorithm
@@ -769,7 +769,7 @@
<span class="md-ellipsis">
Chapter 2. Complexity analysis
Chapter 2. Complexity Analysis
@@ -791,7 +791,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 2. Complexity analysis
Chapter 2. Complexity Analysis
</label>
@@ -813,7 +813,7 @@
<span class="md-ellipsis">
2.1 Algorithm efficiency assessment
2.1 Algorithm Efficiency Evaluation
@@ -841,7 +841,7 @@
<span class="md-ellipsis">
2.2 Iteration and recursion
2.2 Iteration and Recursion
@@ -869,7 +869,7 @@
<span class="md-ellipsis">
2.3 Time complexity
2.3 Time Complexity
@@ -897,7 +897,7 @@
<span class="md-ellipsis">
2.4 Space complexity
2.4 Space Complexity
@@ -990,7 +990,7 @@
<span class="md-ellipsis">
Chapter 3. Data structures
Chapter 3. Data Structures
@@ -1012,7 +1012,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 3. Data structures
Chapter 3. Data Structures
</label>
@@ -1034,7 +1034,7 @@
<span class="md-ellipsis">
3.1 Classification of data structures
3.1 Classification of Data Structures
@@ -1062,7 +1062,7 @@
<span class="md-ellipsis">
3.2 Basic data types
3.2 Basic Data Types
@@ -1090,7 +1090,7 @@
<span class="md-ellipsis">
3.3 Number encoding *
3.3 Number Encoding *
@@ -1118,7 +1118,7 @@
<span class="md-ellipsis">
3.4 Character encoding *
3.4 Character Encoding *
@@ -1211,7 +1211,7 @@
<span class="md-ellipsis">
Chapter 4. Array and linked list
Chapter 4. Array and Linked List
@@ -1233,7 +1233,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 4. Array and linked list
Chapter 4. Array and Linked List
</label>
@@ -1283,7 +1283,7 @@
<span class="md-ellipsis">
4.2 Linked list
4.2 Linked List
@@ -1339,7 +1339,7 @@
<span class="md-ellipsis">
4.4 Memory and cache *
4.4 Memory and Cache *
@@ -1430,7 +1430,7 @@
<span class="md-ellipsis">
Chapter 5. Stack and queue
Chapter 5. Stack and Queue
@@ -1452,7 +1452,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 5. Stack and queue
Chapter 5. Stack and Queue
</label>
@@ -1530,7 +1530,7 @@
<span class="md-ellipsis">
5.3 Double-ended queue
5.3 Double-Ended Queue
@@ -1621,7 +1621,7 @@
<span class="md-ellipsis">
Chapter 6. Hash table
Chapter 6. Hashing
@@ -1643,7 +1643,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 6. Hash table
Chapter 6. Hashing
</label>
@@ -1665,7 +1665,7 @@
<span class="md-ellipsis">
6.1 Hash table
6.1 Hash Table
@@ -1693,7 +1693,7 @@
<span class="md-ellipsis">
6.2 Hash collision
6.2 Hash Collision
@@ -1721,7 +1721,7 @@
<span class="md-ellipsis">
6.3 Hash algorithm
6.3 Hash Algorithm
@@ -1860,7 +1860,7 @@
<span class="md-ellipsis">
7.1 Binary tree
7.1 Binary Tree
@@ -1888,7 +1888,7 @@
<span class="md-ellipsis">
7.2 Binary tree traversal
7.2 Binary Tree Traversal
@@ -1916,7 +1916,7 @@
<span class="md-ellipsis">
7.3 Array Representation of tree
7.3 Array Representation of Tree
@@ -1944,7 +1944,7 @@
<span class="md-ellipsis">
7.4 Binary Search tree
7.4 Binary Search Tree
@@ -1972,7 +1972,7 @@
<span class="md-ellipsis">
7.5 AVL tree *
7.5 AVL Tree *
@@ -2135,7 +2135,7 @@
<span class="md-ellipsis">
8.2 Building a heap
8.2 Building a Heap
@@ -2163,7 +2163,7 @@
<span class="md-ellipsis">
8.3 Top-k problem
8.3 Top-K Problem
@@ -2326,7 +2326,7 @@
<span class="md-ellipsis">
9.2 Basic graph operations
9.2 Basic Operations on Graphs
@@ -2354,7 +2354,7 @@
<span class="md-ellipsis">
9.3 Graph traversal
9.3 Graph Traversal
@@ -2493,7 +2493,7 @@
<span class="md-ellipsis">
10.1 Binary search
10.1 Binary Search
@@ -2521,7 +2521,7 @@
<span class="md-ellipsis">
10.2 Binary search insertion
10.2 Binary Search Insertion
@@ -2549,7 +2549,7 @@
<span class="md-ellipsis">
10.3 Binary search boundaries
10.3 Binary Search Edge Cases
@@ -2577,7 +2577,7 @@
<span class="md-ellipsis">
10.4 Hashing optimization strategies
10.4 Hash Optimization Strategy
@@ -2605,7 +2605,7 @@
<span class="md-ellipsis">
10.5 Search algorithms revisited
10.5 Search Algorithms Revisited
@@ -2754,7 +2754,7 @@
<span class="md-ellipsis">
11.1 Sorting algorithms
11.1 Sorting Algorithms
@@ -2782,7 +2782,7 @@
<span class="md-ellipsis">
11.2 Selection sort
11.2 Selection Sort
@@ -2810,7 +2810,7 @@
<span class="md-ellipsis">
11.3 Bubble sort
11.3 Bubble Sort
@@ -2838,7 +2838,7 @@
<span class="md-ellipsis">
11.4 Insertion sort
11.4 Insertion Sort
@@ -2866,7 +2866,7 @@
<span class="md-ellipsis">
11.5 Quick sort
11.5 Quick Sort
@@ -2894,7 +2894,7 @@
<span class="md-ellipsis">
11.6 Merge sort
11.6 Merge Sort
@@ -2922,7 +2922,7 @@
<span class="md-ellipsis">
11.7 Heap sort
11.7 Heap Sort
@@ -2950,7 +2950,7 @@
<span class="md-ellipsis">
11.8 Bucket sort
11.8 Bucket Sort
@@ -2978,7 +2978,7 @@
<span class="md-ellipsis">
11.9 Counting sort
11.9 Counting Sort
@@ -3006,7 +3006,7 @@
<span class="md-ellipsis">
11.10 Radix sort
11.10 Radix Sort
@@ -3101,7 +3101,7 @@
<span class="md-ellipsis">
Chapter 12. Divide and conquer
Chapter 12. Divide and Conquer
@@ -3123,7 +3123,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 12. Divide and conquer
Chapter 12. Divide and Conquer
</label>
@@ -3154,7 +3154,7 @@
<span class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
@@ -3172,7 +3172,7 @@
<span class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
@@ -3198,10 +3198,10 @@
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#1211-how-to-identify-divide-and-conquer-problems" class="md-nav__link">
<a href="#1211-how-to-determine-divide-and-conquer-problems" class="md-nav__link">
<span class="md-ellipsis">
12.1.1 &nbsp; How to identify divide and conquer problems
12.1.1 &nbsp; How to Determine Divide and Conquer Problems
</span>
</a>
@@ -3209,22 +3209,22 @@
</li>
<li class="md-nav__item">
<a href="#1212-improve-efficiency-through-divide-and-conquer" class="md-nav__link">
<a href="#1212-improving-efficiency-through-divide-and-conquer" class="md-nav__link">
<span class="md-ellipsis">
12.1.2 &nbsp; Improve efficiency through divide and conquer
12.1.2 &nbsp; Improving Efficiency Through Divide and Conquer
</span>
</a>
<nav class="md-nav" aria-label="12.1.2   Improve efficiency through divide and conquer">
<nav class="md-nav" aria-label="12.1.2   Improving Efficiency Through Divide and Conquer">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-optimization-of-operation-count" class="md-nav__link">
<a href="#1-operation-count-optimization" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; Optimization of operation count
1. &nbsp; Operation Count Optimization
</span>
</a>
@@ -3232,10 +3232,10 @@
</li>
<li class="md-nav__item">
<a href="#2-optimization-through-parallel-computation" class="md-nav__link">
<a href="#2-parallel-computation-optimization" class="md-nav__link">
<span class="md-ellipsis">
2. &nbsp; Optimization through parallel computation
2. &nbsp; Parallel Computation Optimization
</span>
</a>
@@ -3251,7 +3251,7 @@
<a href="#1213-common-applications-of-divide-and-conquer" class="md-nav__link">
<span class="md-ellipsis">
12.1.3 &nbsp; Common applications of divide and conquer
12.1.3 &nbsp; Common Applications of Divide and Conquer
</span>
</a>
@@ -3281,7 +3281,7 @@
<span class="md-ellipsis">
12.2 Divide and conquer search strategy
12.2 Divide and Conquer Search Strategy
@@ -3309,7 +3309,7 @@
<span class="md-ellipsis">
12.3 Building binary tree problem
12.3 Building a Binary Tree Problem
@@ -3337,7 +3337,7 @@
<span class="md-ellipsis">
12.4 Tower of Hanoi Problem
12.4 Hanoi Tower Problem
@@ -3474,7 +3474,7 @@
<span class="md-ellipsis">
13.1 Backtracking algorithms
13.1 Backtracking Algorithm
@@ -3502,7 +3502,7 @@
<span class="md-ellipsis">
13.2 Permutation problem
13.2 Permutations Problem
@@ -3530,7 +3530,7 @@
<span class="md-ellipsis">
13.3 Subset sum problem
13.3 Subset-Sum Problem
@@ -3558,7 +3558,7 @@
<span class="md-ellipsis">
13.4 n queens problem
13.4 N-Queens Problem
@@ -3655,7 +3655,7 @@
<span class="md-ellipsis">
Chapter 14. Dynamic programming
Chapter 14. Dynamic Programming
@@ -3677,7 +3677,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 14. Dynamic programming
Chapter 14. Dynamic Programming
</label>
@@ -3699,7 +3699,7 @@
<span class="md-ellipsis">
14.1 Introduction to dynamic programming
14.1 Introduction to Dynamic Programming
@@ -3727,7 +3727,7 @@
<span class="md-ellipsis">
14.2 Characteristics of DP problems
14.2 Characteristics of Dynamic Programming Problems
@@ -3755,7 +3755,7 @@
<span class="md-ellipsis">
14.3 DP problem-solving approach
14.3 Dynamic Programming Problem-Solving Approach
@@ -3783,7 +3783,7 @@
<span class="md-ellipsis">
14.4 0-1 Knapsack problem
14.4 0-1 Knapsack Problem
@@ -3811,7 +3811,7 @@
<span class="md-ellipsis">
14.5 Unbounded knapsack problem
14.5 Unbounded Knapsack Problem
@@ -3839,7 +3839,7 @@
<span class="md-ellipsis">
14.6 Edit distance problem
14.6 Edit Distance Problem
@@ -3976,7 +3976,7 @@
<span class="md-ellipsis">
15.1 Greedy algorithms
15.1 Greedy Algorithm
@@ -4004,7 +4004,7 @@
<span class="md-ellipsis">
15.2 Fractional knapsack problem
15.2 Fractional Knapsack Problem
@@ -4032,7 +4032,7 @@
<span class="md-ellipsis">
15.3 Maximum capacity problem
15.3 Maximum Capacity Problem
@@ -4060,7 +4060,7 @@
<span class="md-ellipsis">
15.4 Maximum product cutting problem
15.4 Maximum Product Cutting Problem
@@ -4193,7 +4193,7 @@
<span class="md-ellipsis">
16.1 Installation
16.1 Programming Environment Installation
@@ -4221,7 +4221,7 @@
<span class="md-ellipsis">
16.2 Contributing
16.2 Contributing Together
@@ -4249,7 +4249,7 @@
<span class="md-ellipsis">
16.3 Terminology
16.3 Terminology Table
@@ -4363,10 +4363,10 @@
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#1211-how-to-identify-divide-and-conquer-problems" class="md-nav__link">
<a href="#1211-how-to-determine-divide-and-conquer-problems" class="md-nav__link">
<span class="md-ellipsis">
12.1.1 &nbsp; How to identify divide and conquer problems
12.1.1 &nbsp; How to Determine Divide and Conquer Problems
</span>
</a>
@@ -4374,22 +4374,22 @@
</li>
<li class="md-nav__item">
<a href="#1212-improve-efficiency-through-divide-and-conquer" class="md-nav__link">
<a href="#1212-improving-efficiency-through-divide-and-conquer" class="md-nav__link">
<span class="md-ellipsis">
12.1.2 &nbsp; Improve efficiency through divide and conquer
12.1.2 &nbsp; Improving Efficiency Through Divide and Conquer
</span>
</a>
<nav class="md-nav" aria-label="12.1.2   Improve efficiency through divide and conquer">
<nav class="md-nav" aria-label="12.1.2   Improving Efficiency Through Divide and Conquer">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-optimization-of-operation-count" class="md-nav__link">
<a href="#1-operation-count-optimization" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; Optimization of operation count
1. &nbsp; Operation Count Optimization
</span>
</a>
@@ -4397,10 +4397,10 @@
</li>
<li class="md-nav__item">
<a href="#2-optimization-through-parallel-computation" class="md-nav__link">
<a href="#2-parallel-computation-optimization" class="md-nav__link">
<span class="md-ellipsis">
2. &nbsp; Optimization through parallel computation
2. &nbsp; Parallel Computation Optimization
</span>
</a>
@@ -4416,7 +4416,7 @@
<a href="#1213-common-applications-of-divide-and-conquer" class="md-nav__link">
<span class="md-ellipsis">
12.1.3 &nbsp; Common applications of divide and conquer
12.1.3 &nbsp; Common Applications of Divide and Conquer
</span>
</a>
@@ -4460,45 +4460,45 @@
<!-- Page content -->
<h1 id="121-divide-and-conquer-algorithms">12.1 &nbsp; Divide and conquer algorithms<a class="headerlink" href="#121-divide-and-conquer-algorithms" title="Permanent link">&para;</a></h1>
<p><u>Divide and conquer</u> is an important and popular algorithm strategy. As the name suggests, the algorithm is typically implemented recursively and consists of two steps: "divide" and "conquer".</p>
<h1 id="121-divide-and-conquer-algorithms">12.1 &nbsp; Divide and Conquer Algorithms<a class="headerlink" href="#121-divide-and-conquer-algorithms" title="Permanent link">&para;</a></h1>
<p><u>Divide and conquer</u> is a very important and common algorithm strategy. Divide and conquer is typically implemented based on recursion, consisting of two steps: "divide" and "conquer".</p>
<ol>
<li><strong>Divide (partition phase)</strong>: Recursively break down the original problem into two or more smaller sub-problems until the smallest sub-problem is reached.</li>
<li><strong>Conquer (merge phase)</strong>: Starting from the smallest sub-problem with known solution, we construct the solution to the original problem by merging the solutions of sub-problems in a bottom-up manner.</li>
<li><strong>Divide (partition phase)</strong>: Recursively divide the original problem into two or more subproblems until the smallest subproblem is reached.</li>
<li><strong>Conquer (merge phase)</strong>: Starting from the smallest subproblems with known solutions, merge the solutions of subproblems from bottom to top to construct the solution to the original problem.</li>
</ol>
<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>
<li><strong>Divide</strong>: Recursively divide the original array (original problem) into two subarrays (subproblems) until the subarray has only one element (smallest subproblem).</li>
<li><strong>Conquer</strong>: Merge the sorted subarrays (solutions to subproblems) from bottom to top to obtain a sorted original array (solution to the original problem).</li>
</ol>
<p><a class="glightbox" href="../divide_and_conquer.assets/divide_and_conquer_merge_sort.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Merge sort's divide and conquer strategy" class="animation-figure" src="../divide_and_conquer.assets/divide_and_conquer_merge_sort.png" /></a></p>
<p align="center"> Figure 12-1 &nbsp; Merge sort's divide and conquer strategy </p>
<p><a class="glightbox" href="../divide_and_conquer.assets/divide_and_conquer_merge_sort.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Divide and conquer strategy of merge sort" class="animation-figure" src="../divide_and_conquer.assets/divide_and_conquer_merge_sort.png" /></a></p>
<p align="center"> Figure 12-1 &nbsp; Divide and conquer strategy of merge sort </p>
<h2 id="1211-how-to-identify-divide-and-conquer-problems">12.1.1 &nbsp; How to identify divide and conquer problems<a class="headerlink" href="#1211-how-to-identify-divide-and-conquer-problems" title="Permanent link">&para;</a></h2>
<p>Whether a problem is suitable for a divide-and-conquer solution can usually be decided based on the following criteria.</p>
<h2 id="1211-how-to-determine-divide-and-conquer-problems">12.1.1 &nbsp; How to Determine Divide and Conquer Problems<a class="headerlink" href="#1211-how-to-determine-divide-and-conquer-problems" title="Permanent link">&para;</a></h2>
<p>Whether a problem is suitable for solving with divide and conquer can usually be determined based on the following criteria.</p>
<ol>
<li><strong>The problem can be broken down into smaller ones</strong>: The original problem can be divided into smaller, similar sub-problems and such process can be recursively done in the same manner.</li>
<li><strong>Sub-problems are independent</strong>: There is no overlap between sub-problems, and they are independent and can be solved separately.</li>
<li><strong>Solutions to sub-problems can be merged</strong>: The solution to the original problem is derived by combining the solutions of the sub-problems.</li>
<li><strong>The problem can be decomposed</strong>: The original problem can be divided into smaller, similar subproblems, and can be recursively divided in the same way.</li>
<li><strong>Subproblems are independent</strong>: There is no overlap between subproblems, they are independent of each other and can be solved independently.</li>
<li><strong>Solutions of subproblems can be merged</strong>: The solution to the original problem is obtained by merging the solutions of subproblems.</li>
</ol>
<p>Clearly, merge sort meets these three criteria.</p>
<p>Clearly, merge sort satisfies these three criteria.</p>
<ol>
<li><strong>The problem can be broken down into smaller ones</strong>: Recursively divide the array (original problem) into two sub-arrays (sub-problems).</li>
<li><strong>Sub-problems are independent</strong>: Each sub-array can be sorted independently (sub-problems can be solved independently).</li>
<li><strong>Solutions to sub-problems can be merged</strong>: Two ordered sub-arrays (solutions to the sub-problems) can be merged into one ordered array (solution to the original problem).</li>
<li><strong>The problem can be decomposed</strong>: Recursively divide the array (original problem) into two subarrays (subproblems).</li>
<li><strong>Subproblems are independent</strong>: Each subarray can be sorted independently (subproblems can be solved independently).</li>
<li><strong>Solutions of subproblems can be merged</strong>: Two sorted subarrays (solutions of subproblems) can be merged into one sorted array (solution of the original problem).</li>
</ol>
<h2 id="1212-improve-efficiency-through-divide-and-conquer">12.1.2 &nbsp; Improve efficiency through divide and conquer<a class="headerlink" href="#1212-improve-efficiency-through-divide-and-conquer" title="Permanent link">&para;</a></h2>
<p>The <strong>divide-and-conquer strategy not only effectively solves algorithm problems but also often enhances efficiency</strong>. In sorting algorithms, quick sort, merge sort, and heap sort are faster than selection sort, bubble sort, and insertion sort because they apply the divide-and-conquer strategy.</p>
<p>We may have a question in mind: <strong>Why can divide and conquer improve algorithm efficiency, and what is the underlying logic?</strong> In other words, why is breaking a problem into sub-problems, solving them, and combining their solutions to address the original problem offer more efficiency than directly solving the original problem? This question can be analyzed from two aspects: operation count 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 Figure 12-2, such 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. Thus, the overall time complexity is:</p>
<h2 id="1212-improving-efficiency-through-divide-and-conquer">12.1.2 &nbsp; Improving Efficiency Through Divide and Conquer<a class="headerlink" href="#1212-improving-efficiency-through-divide-and-conquer" title="Permanent link">&para;</a></h2>
<p><strong>Divide and conquer can not only effectively solve algorithmic problems but often also improve algorithm efficiency</strong>. In sorting algorithms, quick sort, merge sort, and heap sort are faster than selection, bubble, and insertion sort because they apply the divide and conquer strategy.</p>
<p>This raises the question: <strong>Why can divide and conquer improve algorithm efficiency, and what is the underlying logic</strong>? In other words, why is dividing a large problem into multiple subproblems, solving the subproblems, and merging their solutions more efficient than directly solving the original problem? This question can be discussed from two aspects: operation count and parallel computation.</p>
<h3 id="1-operation-count-optimization">1. &nbsp; Operation Count Optimization<a class="headerlink" href="#1-operation-count-optimization" title="Permanent link">&para;</a></h3>
<p>Taking "bubble sort" as an example, processing an array of length <span class="arithmatex">\(n\)</span> requires <span class="arithmatex">\(O(n^2)\)</span> time. Suppose we divide the array into two subarrays from the midpoint as shown in Figure 12-2, the division requires <span class="arithmatex">\(O(n)\)</span> time, sorting each subarray requires <span class="arithmatex">\(O((n / 2)^2)\)</span> time, and merging the two subarrays requires <span class="arithmatex">\(O(n)\)</span> time, resulting in an overall time complexity of:</p>
<div class="arithmatex">\[
O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n)
\]</div>
<p><a class="glightbox" href="../divide_and_conquer.assets/divide_and_conquer_bubble_sort.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Bubble sort before and after array partition" class="animation-figure" src="../divide_and_conquer.assets/divide_and_conquer_bubble_sort.png" /></a></p>
<p align="center"> Figure 12-2 &nbsp; Bubble sort before and after array partition </p>
<p><a class="glightbox" href="../divide_and_conquer.assets/divide_and_conquer_bubble_sort.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Bubble sort before and after array division" class="animation-figure" src="../divide_and_conquer.assets/divide_and_conquer_bubble_sort.png" /></a></p>
<p align="center"> Figure 12-2 &nbsp; Bubble sort before and after array division </p>
<p>Let's calculate the following inequality, where the left side represents the total number of operations before division and the right side represents the total number of operations after division, respectively:</p>
<p>Next, we compute the following inequality, where the left and right sides represent the total number of operations before and after division, respectively:</p>
<div class="arithmatex">\[
\begin{aligned}
n^2 &amp; &gt; \frac{n^2}{2} + 2n \newline
@@ -4506,36 +4506,36 @@ n^2 - \frac{n^2}{2} - 2n &amp; &gt; 0 \newline
n(n - 4) &amp; &gt; 0
\end{aligned}
\]</div>
<p><strong>This means that when <span class="arithmatex">\(n &gt; 4\)</span>, the number of operations after partitioning is fewer, leading to better performance</strong>. Please note that the time complexity after partitioning is still quadratic <span class="arithmatex">\(O(n^2)\)</span>, but the constant factor in the complexity has decreased.</p>
<p>We can go even further. <strong>How about keeping dividing the sub-arrays from their midpoints into two sub-arrays</strong> until the sub-arrays have only one element left? This idea is actually "merge sort," with a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>.</p>
<p>Let's try something a bit different again. <strong>How about splitting into more partitions instead of just two?</strong> For example, we evenly divide the original array into <span class="arithmatex">\(k\)</span> sub-arrays? This approach is very similar to "bucket sort," which is very suitable for sorting massive data. Theoretically, the time complexity can reach <span class="arithmatex">\(O(n + k)\)</span>.</p>
<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>which means that they can be solved in parallel.</strong> As a result, divide and conquer not only reduces the algorithm's time complexity, <strong>but also facilitates parallel optimization by modern operating systems.</strong></p>
<p>Parallel optimization is particularly effective in environments with multiple cores or processors. As the system can process multiple sub-problems simultaneously, fully utilizing computing resources, the overall runtime is significantly reduced.</p>
<p>For example, in the "bucket sort" shown in Figure 12-3, we break massive data evenly into various buckets. The jobs of sorting each bucket can be allocated to available computing units. Once all jobs are done, all sorted buckets are merged to produce the final result.</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>
<p><strong>This means that when <span class="arithmatex">\(n &gt; 4\)</span>, the number of operations after division is smaller, and sorting efficiency should be higher</strong>. Note that the time complexity after division is still quadratic <span class="arithmatex">\(O(n^2)\)</span>, but the constant term in the complexity has become smaller.</p>
<p>Going further, <strong>what if we continuously divide the subarrays from their midpoints into two subarrays</strong> until the subarrays have only one element? This approach is actually "merge sort", with a time complexity of <span class="arithmatex">\(O(n \log n)\)</span>.</p>
<p>Thinking further, <strong>what if we set multiple division points</strong> and evenly divide the original array into <span class="arithmatex">\(k\)</span> subarrays? This situation is very similar to "bucket sort", which is well-suited for sorting massive amounts of data, with a theoretical time complexity of <span class="arithmatex">\(O(n + k)\)</span>.</p>
<h3 id="2-parallel-computation-optimization">2. &nbsp; Parallel Computation Optimization<a class="headerlink" href="#2-parallel-computation-optimization" title="Permanent link">&para;</a></h3>
<p>We know that the subproblems generated by divide and conquer are independent of each other, <strong>so they can typically be solved in parallel</strong>. This means divide and conquer can not only reduce the time complexity of algorithms, <strong>but also benefits from parallel optimization by operating systems</strong>.</p>
<p>Parallel optimization is particularly effective in multi-core or multi-processor environments, as the system can simultaneously handle multiple subproblems, making fuller use of computing resources and significantly reducing overall runtime.</p>
<p>For example, in the "bucket sort" shown in Figure 12-3, we evenly distribute massive data into various buckets, and the sorting tasks for all buckets can be distributed to various computing units. After completion, the results are merged.</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="Parallel computation in bucket sort" class="animation-figure" src="../divide_and_conquer.assets/divide_and_conquer_parallel_computing.png" /></a></p>
<p align="center"> Figure 12-3 &nbsp; Parallel computation in bucket sort </p>
<h2 id="1213-common-applications-of-divide-and-conquer">12.1.3 &nbsp; Common applications of divide and conquer<a class="headerlink" href="#1213-common-applications-of-divide-and-conquer" title="Permanent link">&para;</a></h2>
<p>Divide and conquer can be used to solve many classic algorithm problems.</p>
<h2 id="1213-common-applications-of-divide-and-conquer">12.1.3 &nbsp; Common Applications of Divide and Conquer<a class="headerlink" href="#1213-common-applications-of-divide-and-conquer" title="Permanent link">&para;</a></h2>
<p>On one hand, divide and conquer can be used to solve many classic algorithmic problems.</p>
<ul>
<li><strong>Finding the closest pair of points</strong>: This algorithm works by dividing the set of points into two halves. Then it recursively finds the closest pair in each half. Finally it considers pairs that span the two halves to find the overall closest pair.</li>
<li><strong>Large integer multiplication</strong>: One algorithm is called Karatsuba. It breaks down large integer multiplication into several smaller integer multiplications and additions.</li>
<li><strong>Matrix multiplication</strong>: One example is the Strassen algorithm. It breaks down a large matrix multiplication into multiple small matrix multiplications and additions.</li>
<li><strong>Tower of Hanoi problem</strong>: The Tower of Hanoi problem can be solved recursively, a typical application of the divide-and-conquer strategy.</li>
<li><strong>Solving inversion pairs</strong>: In a sequence, if a preceding number is greater than a following number, then these two numbers constitute an inversion pair. Solving inversion pair problem can utilize the idea of divide and conquer, with the aid of merge sort.</li>
<li><strong>Finding the closest pair of points</strong>: This algorithm first divides the point set into two parts, then finds the closest pair of points in each part separately, and finally finds the closest pair of points that spans both parts.</li>
<li><strong>Large integer multiplication</strong>: For example, the Karatsuba algorithm, which decomposes large integer multiplication into several smaller integer multiplications and additions.</li>
<li><strong>Matrix multiplication</strong>: For example, the Strassen algorithm, which decomposes large matrix multiplication into multiple small matrix multiplications and additions.</li>
<li><strong>Hanota problem</strong>: The hanota problem can be solved through recursion, which is a typical application of the divide and conquer strategy.</li>
<li><strong>Solving inversion pairs</strong>: In a sequence, if a preceding number is greater than a following number, these two numbers form an inversion pair. Solving the inversion pair problem can utilize the divide and conquer approach with the help of merge sort.</li>
</ul>
<p>Divide and conquer is also widely applied in the design of algorithms and data structures.</p>
<p>On the other hand, divide and conquer is widely applied in the design of algorithms and data structures.</p>
<ul>
<li><strong>Binary search</strong>: Binary search divides a sorted array into two halves from the midpoint index. And then based on the comparison result between the target value and the middle element value, one half is discarded. The search continues on the remaining half with the same process until the target is found or there is no remaining element.</li>
<li><strong>Merge sort</strong>: Already introduced at the beginning of this section, no further elaboration is needed.</li>
<li><strong>Quicksort</strong>: Quicksort picks a pivot value to divide the array into two sub-arrays, one with elements smaller than the pivot and the other with elements larger than the pivot. Such process goes on against each of these two sub-arrays until they hold only one element.</li>
<li><strong>Bucket sort</strong>: The basic idea of bucket sort is to distribute data to multiple buckets. After sorting the elements within each bucket, retrieve the elements from the buckets in order to obtain an ordered array.</li>
<li><strong>Trees</strong>: For example, binary search trees, AVL trees, red-black trees, B-trees, and B+ trees, etc. Their operations, such as search, insertion, and deletion, can all be regarded as applications of the divide-and-conquer strategy.</li>
<li><strong>Heap</strong>: A heap is a special type of complete binary tree. Its various operations, such as insertion, deletion, and heapify, actually imply the idea of divide and conquer.</li>
<li><strong>Hash table</strong>: Although hash tables do not directly apply divide and conquer, some hash collision resolution solutions indirectly apply the strategy. For example, long lists in chained addressing may be converted to red-black trees to improve query efficiency.</li>
<li><strong>Binary search</strong>: Binary search divides a sorted array into two parts from the midpoint index, then decides which half to eliminate based on the comparison result between the target value and the middle element value, and performs the same binary operation on the remaining interval.</li>
<li><strong>Merge sort</strong>: Already introduced at the beginning of this section, no further elaboration needed.</li>
<li><strong>Quick sort</strong>: Quick sort selects a pivot value, then divides the array into two subarrays, one with elements smaller than the pivot and the other with elements larger than the pivot, then performs the same division operation on these two parts until the subarrays have only one element.</li>
<li><strong>Bucket sort</strong>: The basic idea of bucket sort is to scatter data into multiple buckets, then sort the elements within each bucket, and finally extract the elements from each bucket in sequence to obtain a sorted array.</li>
<li><strong>Trees</strong>: For example, binary search trees, AVL trees, red-black trees, B-trees, B+ trees, etc. Their search, insertion, and deletion operations can all be viewed as applications of the divide and conquer strategy.</li>
<li><strong>Heaps</strong>: A heap is a special complete binary tree, and its various operations, such as insertion, deletion, and heapify, actually imply the divide and conquer idea.</li>
<li><strong>Hash tables</strong>: Although hash tables do not directly apply divide and conquer, some hash collision resolution solutions indirectly apply the divide and conquer strategy. For example, long linked lists in chaining may be converted to red-black trees to improve query efficiency.</li>
</ul>
<p>It can be seen that <strong>divide and conquer is a subtly pervasive algorithmic idea</strong>, embedded within various algorithms and data structures.</p>
<p>It can be seen that <strong>divide and conquer is a "subtly pervasive" algorithmic idea</strong>, embedded in various algorithms and data structures.</p>
<!-- Source file information -->
@@ -4558,7 +4558,7 @@ aria-label="Footer"
<a
href="../"
class="md-footer__link md-footer__link--prev"
aria-label="Previous: Chapter 12. &amp;nbsp; Divide and conquer"
aria-label="Previous: Chapter 12. &amp;nbsp; Divide and Conquer"
rel="prev"
>
<div class="md-footer__button md-icon">
@@ -4570,7 +4570,7 @@ aria-label="Footer"
Previous
</span>
<div class="md-ellipsis">
Chapter 12. &nbsp; Divide and conquer
Chapter 12. &nbsp; Divide and Conquer
</div>
</div>
</a>
@@ -4582,7 +4582,7 @@ aria-label="Footer"
<a
href="../binary_search_recur/"
class="md-footer__link md-footer__link--next"
aria-label="Next: 12.2 Divide and conquer search strategy"
aria-label="Next: 12.2 Divide and Conquer Search Strategy"
rel="next"
>
<div class="md-footer__title">
@@ -4590,7 +4590,7 @@ aria-label="Footer"
Next
</span>
<div class="md-ellipsis">
12.2 Divide and conquer search strategy
12.2 Divide and Conquer Search Strategy
</div>
</div>
<div class="md-footer__button md-icon">
@@ -4683,7 +4683,7 @@ aria-label="Footer"
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../" class="md-footer__link md-footer__link--prev" aria-label="Previous: Chapter 12. &amp;nbsp; Divide and conquer">
<a href="../" class="md-footer__link md-footer__link--prev" aria-label="Previous: Chapter 12. &amp;nbsp; Divide and Conquer">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
@@ -4693,20 +4693,20 @@ aria-label="Footer"
Previous
</span>
<div class="md-ellipsis">
Chapter 12. &nbsp; Divide and conquer
Chapter 12. &nbsp; Divide and Conquer
</div>
</div>
</a>
<a href="../binary_search_recur/" class="md-footer__link md-footer__link--next" aria-label="Next: 12.2 Divide and conquer search strategy">
<a href="../binary_search_recur/" class="md-footer__link md-footer__link--next" aria-label="Next: 12.2 Divide and Conquer Search Strategy">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
12.2 Divide and conquer search strategy
12.2 Divide and Conquer Search Strategy
</div>
</div>
<div class="md-footer__button md-icon">
File diff suppressed because it is too large Load Diff
+96 -96
View File
@@ -37,7 +37,7 @@
<title>Chapter 12.   Divide and conquer - Hello Algo</title>
<title>Chapter 12.   Divide and Conquer - Hello Algo</title>
@@ -58,8 +58,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Lato";--md-code-font:"JetBrains Mono"}</style>
@@ -154,7 +154,7 @@
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Chapter 12. &nbsp; Divide and conquer
Chapter 12. &nbsp; Divide and Conquer
</span>
</div>
@@ -371,7 +371,7 @@
<span class="md-ellipsis">
Before starting
Before Starting
@@ -388,7 +388,7 @@
<span class="md-nav__icon md-icon"></span>
Before starting
Before Starting
</label>
@@ -487,7 +487,7 @@
<span class="md-ellipsis">
0.1 About this book
0.1 About This Book
@@ -515,7 +515,7 @@
<span class="md-ellipsis">
0.2 How to read
0.2 How to Use This Book
@@ -604,7 +604,7 @@
<span class="md-ellipsis">
Chapter 1. Encounter with algorithms
Chapter 1. Encounter With Algorithms
@@ -626,7 +626,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 1. Encounter with algorithms
Chapter 1. Encounter With Algorithms
</label>
@@ -648,7 +648,7 @@
<span class="md-ellipsis">
1.1 Algorithms are everywhere
1.1 Algorithms Are Everywhere
@@ -676,7 +676,7 @@
<span class="md-ellipsis">
1.2 What is an algorithm
1.2 What Is an Algorithm
@@ -769,7 +769,7 @@
<span class="md-ellipsis">
Chapter 2. Complexity analysis
Chapter 2. Complexity Analysis
@@ -791,7 +791,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 2. Complexity analysis
Chapter 2. Complexity Analysis
</label>
@@ -813,7 +813,7 @@
<span class="md-ellipsis">
2.1 Algorithm efficiency assessment
2.1 Algorithm Efficiency Evaluation
@@ -841,7 +841,7 @@
<span class="md-ellipsis">
2.2 Iteration and recursion
2.2 Iteration and Recursion
@@ -869,7 +869,7 @@
<span class="md-ellipsis">
2.3 Time complexity
2.3 Time Complexity
@@ -897,7 +897,7 @@
<span class="md-ellipsis">
2.4 Space complexity
2.4 Space Complexity
@@ -990,7 +990,7 @@
<span class="md-ellipsis">
Chapter 3. Data structures
Chapter 3. Data Structures
@@ -1012,7 +1012,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 3. Data structures
Chapter 3. Data Structures
</label>
@@ -1034,7 +1034,7 @@
<span class="md-ellipsis">
3.1 Classification of data structures
3.1 Classification of Data Structures
@@ -1062,7 +1062,7 @@
<span class="md-ellipsis">
3.2 Basic data types
3.2 Basic Data Types
@@ -1090,7 +1090,7 @@
<span class="md-ellipsis">
3.3 Number encoding *
3.3 Number Encoding *
@@ -1118,7 +1118,7 @@
<span class="md-ellipsis">
3.4 Character encoding *
3.4 Character Encoding *
@@ -1211,7 +1211,7 @@
<span class="md-ellipsis">
Chapter 4. Array and linked list
Chapter 4. Array and Linked List
@@ -1233,7 +1233,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 4. Array and linked list
Chapter 4. Array and Linked List
</label>
@@ -1283,7 +1283,7 @@
<span class="md-ellipsis">
4.2 Linked list
4.2 Linked List
@@ -1339,7 +1339,7 @@
<span class="md-ellipsis">
4.4 Memory and cache *
4.4 Memory and Cache *
@@ -1430,7 +1430,7 @@
<span class="md-ellipsis">
Chapter 5. Stack and queue
Chapter 5. Stack and Queue
@@ -1452,7 +1452,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 5. Stack and queue
Chapter 5. Stack and Queue
</label>
@@ -1530,7 +1530,7 @@
<span class="md-ellipsis">
5.3 Double-ended queue
5.3 Double-Ended Queue
@@ -1621,7 +1621,7 @@
<span class="md-ellipsis">
Chapter 6. Hash table
Chapter 6. Hashing
@@ -1643,7 +1643,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 6. Hash table
Chapter 6. Hashing
</label>
@@ -1665,7 +1665,7 @@
<span class="md-ellipsis">
6.1 Hash table
6.1 Hash Table
@@ -1693,7 +1693,7 @@
<span class="md-ellipsis">
6.2 Hash collision
6.2 Hash Collision
@@ -1721,7 +1721,7 @@
<span class="md-ellipsis">
6.3 Hash algorithm
6.3 Hash Algorithm
@@ -1860,7 +1860,7 @@
<span class="md-ellipsis">
7.1 Binary tree
7.1 Binary Tree
@@ -1888,7 +1888,7 @@
<span class="md-ellipsis">
7.2 Binary tree traversal
7.2 Binary Tree Traversal
@@ -1916,7 +1916,7 @@
<span class="md-ellipsis">
7.3 Array Representation of tree
7.3 Array Representation of Tree
@@ -1944,7 +1944,7 @@
<span class="md-ellipsis">
7.4 Binary Search tree
7.4 Binary Search Tree
@@ -1972,7 +1972,7 @@
<span class="md-ellipsis">
7.5 AVL tree *
7.5 AVL Tree *
@@ -2135,7 +2135,7 @@
<span class="md-ellipsis">
8.2 Building a heap
8.2 Building a Heap
@@ -2163,7 +2163,7 @@
<span class="md-ellipsis">
8.3 Top-k problem
8.3 Top-K Problem
@@ -2326,7 +2326,7 @@
<span class="md-ellipsis">
9.2 Basic graph operations
9.2 Basic Operations on Graphs
@@ -2354,7 +2354,7 @@
<span class="md-ellipsis">
9.3 Graph traversal
9.3 Graph Traversal
@@ -2493,7 +2493,7 @@
<span class="md-ellipsis">
10.1 Binary search
10.1 Binary Search
@@ -2521,7 +2521,7 @@
<span class="md-ellipsis">
10.2 Binary search insertion
10.2 Binary Search Insertion
@@ -2549,7 +2549,7 @@
<span class="md-ellipsis">
10.3 Binary search boundaries
10.3 Binary Search Edge Cases
@@ -2577,7 +2577,7 @@
<span class="md-ellipsis">
10.4 Hashing optimization strategies
10.4 Hash Optimization Strategy
@@ -2605,7 +2605,7 @@
<span class="md-ellipsis">
10.5 Search algorithms revisited
10.5 Search Algorithms Revisited
@@ -2754,7 +2754,7 @@
<span class="md-ellipsis">
11.1 Sorting algorithms
11.1 Sorting Algorithms
@@ -2782,7 +2782,7 @@
<span class="md-ellipsis">
11.2 Selection sort
11.2 Selection Sort
@@ -2810,7 +2810,7 @@
<span class="md-ellipsis">
11.3 Bubble sort
11.3 Bubble Sort
@@ -2838,7 +2838,7 @@
<span class="md-ellipsis">
11.4 Insertion sort
11.4 Insertion Sort
@@ -2866,7 +2866,7 @@
<span class="md-ellipsis">
11.5 Quick sort
11.5 Quick Sort
@@ -2894,7 +2894,7 @@
<span class="md-ellipsis">
11.6 Merge sort
11.6 Merge Sort
@@ -2922,7 +2922,7 @@
<span class="md-ellipsis">
11.7 Heap sort
11.7 Heap Sort
@@ -2950,7 +2950,7 @@
<span class="md-ellipsis">
11.8 Bucket sort
11.8 Bucket Sort
@@ -2978,7 +2978,7 @@
<span class="md-ellipsis">
11.9 Counting sort
11.9 Counting Sort
@@ -3006,7 +3006,7 @@
<span class="md-ellipsis">
11.10 Radix sort
11.10 Radix Sort
@@ -3101,7 +3101,7 @@
<span class="md-ellipsis">
Chapter 12. Divide and conquer
Chapter 12. Divide and Conquer
@@ -3123,7 +3123,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 12. Divide and conquer
Chapter 12. Divide and Conquer
</label>
@@ -3145,7 +3145,7 @@
<span class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
@@ -3173,7 +3173,7 @@
<span class="md-ellipsis">
12.2 Divide and conquer search strategy
12.2 Divide and Conquer Search Strategy
@@ -3201,7 +3201,7 @@
<span class="md-ellipsis">
12.3 Building binary tree problem
12.3 Building a Binary Tree Problem
@@ -3229,7 +3229,7 @@
<span class="md-ellipsis">
12.4 Tower of Hanoi Problem
12.4 Hanoi Tower Problem
@@ -3366,7 +3366,7 @@
<span class="md-ellipsis">
13.1 Backtracking algorithms
13.1 Backtracking Algorithm
@@ -3394,7 +3394,7 @@
<span class="md-ellipsis">
13.2 Permutation problem
13.2 Permutations Problem
@@ -3422,7 +3422,7 @@
<span class="md-ellipsis">
13.3 Subset sum problem
13.3 Subset-Sum Problem
@@ -3450,7 +3450,7 @@
<span class="md-ellipsis">
13.4 n queens problem
13.4 N-Queens Problem
@@ -3547,7 +3547,7 @@
<span class="md-ellipsis">
Chapter 14. Dynamic programming
Chapter 14. Dynamic Programming
@@ -3569,7 +3569,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 14. Dynamic programming
Chapter 14. Dynamic Programming
</label>
@@ -3591,7 +3591,7 @@
<span class="md-ellipsis">
14.1 Introduction to dynamic programming
14.1 Introduction to Dynamic Programming
@@ -3619,7 +3619,7 @@
<span class="md-ellipsis">
14.2 Characteristics of DP problems
14.2 Characteristics of Dynamic Programming Problems
@@ -3647,7 +3647,7 @@
<span class="md-ellipsis">
14.3 DP problem-solving approach
14.3 Dynamic Programming Problem-Solving Approach
@@ -3675,7 +3675,7 @@
<span class="md-ellipsis">
14.4 0-1 Knapsack problem
14.4 0-1 Knapsack Problem
@@ -3703,7 +3703,7 @@
<span class="md-ellipsis">
14.5 Unbounded knapsack problem
14.5 Unbounded Knapsack Problem
@@ -3731,7 +3731,7 @@
<span class="md-ellipsis">
14.6 Edit distance problem
14.6 Edit Distance Problem
@@ -3868,7 +3868,7 @@
<span class="md-ellipsis">
15.1 Greedy algorithms
15.1 Greedy Algorithm
@@ -3896,7 +3896,7 @@
<span class="md-ellipsis">
15.2 Fractional knapsack problem
15.2 Fractional Knapsack Problem
@@ -3924,7 +3924,7 @@
<span class="md-ellipsis">
15.3 Maximum capacity problem
15.3 Maximum Capacity Problem
@@ -3952,7 +3952,7 @@
<span class="md-ellipsis">
15.4 Maximum product cutting problem
15.4 Maximum Product Cutting Problem
@@ -4085,7 +4085,7 @@
<span class="md-ellipsis">
16.1 Installation
16.1 Programming Environment Installation
@@ -4113,7 +4113,7 @@
<span class="md-ellipsis">
16.2 Contributing
16.2 Contributing Together
@@ -4141,7 +4141,7 @@
<span class="md-ellipsis">
16.3 Terminology
16.3 Terminology Table
@@ -4302,19 +4302,19 @@
<!-- Page content -->
<h1 id="chapter-12-divide-and-conquer">Chapter 12. &nbsp; Divide and conquer<a class="headerlink" href="#chapter-12-divide-and-conquer" title="Permanent link">&para;</a></h1>
<p><a class="glightbox" href="../assets/covers/chapter_divide_and_conquer.jpg" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Divide and Conquer" class="cover-image" src="../assets/covers/chapter_divide_and_conquer.jpg" /></a></p>
<h1 id="chapter-12-divide-and-conquer">Chapter 12. &nbsp; Divide and Conquer<a class="headerlink" href="#chapter-12-divide-and-conquer" title="Permanent link">&para;</a></h1>
<p><a class="glightbox" href="../assets/covers/chapter_divide_and_conquer.jpg" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Divide and conquer" class="cover-image" src="../assets/covers/chapter_divide_and_conquer.jpg" /></a></p>
<div class="admonition abstract">
<p class="admonition-title">Abstract</p>
<p>Difficult problems are decomposed layer by layer, with each decomposition making them simpler.</p>
<p>Divide and conquer unveils a profound truth: begin with simplicity, and complexity dissolves.</p>
<p>Divide and conquer reveals an important truth: start with simplicity, and nothing remains complex.</p>
</div>
<h2 id="chapter-contents">Chapter contents<a class="headerlink" href="#chapter-contents" title="Permanent link">&para;</a></h2>
<ul>
<li><a href="divide_and_conquer/">12.1 &nbsp; Divide and conquer algorithms</a></li>
<li><a href="binary_search_recur/">12.2 &nbsp; Divide and conquer search strategy</a></li>
<li><a href="build_binary_tree_problem/">12.3 &nbsp; Building binary tree problem</a></li>
<li><a href="hanota_problem/">12.4 &nbsp; Tower of Hanoi Problem</a></li>
<li><a href="divide_and_conquer/">12.1 &nbsp; Divide and Conquer Algorithms</a></li>
<li><a href="binary_search_recur/">12.2 &nbsp; Divide and Conquer Search Strategy</a></li>
<li><a href="build_binary_tree_problem/">12.3 &nbsp; Building a Binary Tree Problem</a></li>
<li><a href="hanota_problem/">12.4 &nbsp; Hanoi Tower Problem</a></li>
<li><a href="summary/">12.5 &nbsp; Summary</a></li>
</ul>
@@ -4363,7 +4363,7 @@ aria-label="Footer"
<a
href="divide_and_conquer/"
class="md-footer__link md-footer__link--next"
aria-label="Next: 12.1 Divide and conquer algorithms"
aria-label="Next: 12.1 Divide and Conquer Algorithms"
rel="next"
>
<div class="md-footer__title">
@@ -4371,7 +4371,7 @@ aria-label="Footer"
Next
</span>
<div class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
</div>
</div>
<div class="md-footer__button md-icon">
@@ -4481,13 +4481,13 @@ aria-label="Footer"
<a href="divide_and_conquer/" class="md-footer__link md-footer__link--next" aria-label="Next: 12.1 Divide and conquer algorithms">
<a href="divide_and_conquer/" class="md-footer__link md-footer__link--next" aria-label="Next: 12.1 Divide and Conquer Algorithms">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
</div>
</div>
<div class="md-footer__button md-icon">
+164 -96
View File
@@ -58,8 +58,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Lato";--md-code-font:"JetBrains Mono"}</style>
@@ -371,7 +371,7 @@
<span class="md-ellipsis">
Before starting
Before Starting
@@ -388,7 +388,7 @@
<span class="md-nav__icon md-icon"></span>
Before starting
Before Starting
</label>
@@ -487,7 +487,7 @@
<span class="md-ellipsis">
0.1 About this book
0.1 About This Book
@@ -515,7 +515,7 @@
<span class="md-ellipsis">
0.2 How to read
0.2 How to Use This Book
@@ -604,7 +604,7 @@
<span class="md-ellipsis">
Chapter 1. Encounter with algorithms
Chapter 1. Encounter With Algorithms
@@ -626,7 +626,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 1. Encounter with algorithms
Chapter 1. Encounter With Algorithms
</label>
@@ -648,7 +648,7 @@
<span class="md-ellipsis">
1.1 Algorithms are everywhere
1.1 Algorithms Are Everywhere
@@ -676,7 +676,7 @@
<span class="md-ellipsis">
1.2 What is an algorithm
1.2 What Is an Algorithm
@@ -769,7 +769,7 @@
<span class="md-ellipsis">
Chapter 2. Complexity analysis
Chapter 2. Complexity Analysis
@@ -791,7 +791,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 2. Complexity analysis
Chapter 2. Complexity Analysis
</label>
@@ -813,7 +813,7 @@
<span class="md-ellipsis">
2.1 Algorithm efficiency assessment
2.1 Algorithm Efficiency Evaluation
@@ -841,7 +841,7 @@
<span class="md-ellipsis">
2.2 Iteration and recursion
2.2 Iteration and Recursion
@@ -869,7 +869,7 @@
<span class="md-ellipsis">
2.3 Time complexity
2.3 Time Complexity
@@ -897,7 +897,7 @@
<span class="md-ellipsis">
2.4 Space complexity
2.4 Space Complexity
@@ -990,7 +990,7 @@
<span class="md-ellipsis">
Chapter 3. Data structures
Chapter 3. Data Structures
@@ -1012,7 +1012,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 3. Data structures
Chapter 3. Data Structures
</label>
@@ -1034,7 +1034,7 @@
<span class="md-ellipsis">
3.1 Classification of data structures
3.1 Classification of Data Structures
@@ -1062,7 +1062,7 @@
<span class="md-ellipsis">
3.2 Basic data types
3.2 Basic Data Types
@@ -1090,7 +1090,7 @@
<span class="md-ellipsis">
3.3 Number encoding *
3.3 Number Encoding *
@@ -1118,7 +1118,7 @@
<span class="md-ellipsis">
3.4 Character encoding *
3.4 Character Encoding *
@@ -1211,7 +1211,7 @@
<span class="md-ellipsis">
Chapter 4. Array and linked list
Chapter 4. Array and Linked List
@@ -1233,7 +1233,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 4. Array and linked list
Chapter 4. Array and Linked List
</label>
@@ -1283,7 +1283,7 @@
<span class="md-ellipsis">
4.2 Linked list
4.2 Linked List
@@ -1339,7 +1339,7 @@
<span class="md-ellipsis">
4.4 Memory and cache *
4.4 Memory and Cache *
@@ -1430,7 +1430,7 @@
<span class="md-ellipsis">
Chapter 5. Stack and queue
Chapter 5. Stack and Queue
@@ -1452,7 +1452,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 5. Stack and queue
Chapter 5. Stack and Queue
</label>
@@ -1530,7 +1530,7 @@
<span class="md-ellipsis">
5.3 Double-ended queue
5.3 Double-Ended Queue
@@ -1621,7 +1621,7 @@
<span class="md-ellipsis">
Chapter 6. Hash table
Chapter 6. Hashing
@@ -1643,7 +1643,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 6. Hash table
Chapter 6. Hashing
</label>
@@ -1665,7 +1665,7 @@
<span class="md-ellipsis">
6.1 Hash table
6.1 Hash Table
@@ -1693,7 +1693,7 @@
<span class="md-ellipsis">
6.2 Hash collision
6.2 Hash Collision
@@ -1721,7 +1721,7 @@
<span class="md-ellipsis">
6.3 Hash algorithm
6.3 Hash Algorithm
@@ -1860,7 +1860,7 @@
<span class="md-ellipsis">
7.1 Binary tree
7.1 Binary Tree
@@ -1888,7 +1888,7 @@
<span class="md-ellipsis">
7.2 Binary tree traversal
7.2 Binary Tree Traversal
@@ -1916,7 +1916,7 @@
<span class="md-ellipsis">
7.3 Array Representation of tree
7.3 Array Representation of Tree
@@ -1944,7 +1944,7 @@
<span class="md-ellipsis">
7.4 Binary Search tree
7.4 Binary Search Tree
@@ -1972,7 +1972,7 @@
<span class="md-ellipsis">
7.5 AVL tree *
7.5 AVL Tree *
@@ -2135,7 +2135,7 @@
<span class="md-ellipsis">
8.2 Building a heap
8.2 Building a Heap
@@ -2163,7 +2163,7 @@
<span class="md-ellipsis">
8.3 Top-k problem
8.3 Top-K Problem
@@ -2326,7 +2326,7 @@
<span class="md-ellipsis">
9.2 Basic graph operations
9.2 Basic Operations on Graphs
@@ -2354,7 +2354,7 @@
<span class="md-ellipsis">
9.3 Graph traversal
9.3 Graph Traversal
@@ -2493,7 +2493,7 @@
<span class="md-ellipsis">
10.1 Binary search
10.1 Binary Search
@@ -2521,7 +2521,7 @@
<span class="md-ellipsis">
10.2 Binary search insertion
10.2 Binary Search Insertion
@@ -2549,7 +2549,7 @@
<span class="md-ellipsis">
10.3 Binary search boundaries
10.3 Binary Search Edge Cases
@@ -2577,7 +2577,7 @@
<span class="md-ellipsis">
10.4 Hashing optimization strategies
10.4 Hash Optimization Strategy
@@ -2605,7 +2605,7 @@
<span class="md-ellipsis">
10.5 Search algorithms revisited
10.5 Search Algorithms Revisited
@@ -2754,7 +2754,7 @@
<span class="md-ellipsis">
11.1 Sorting algorithms
11.1 Sorting Algorithms
@@ -2782,7 +2782,7 @@
<span class="md-ellipsis">
11.2 Selection sort
11.2 Selection Sort
@@ -2810,7 +2810,7 @@
<span class="md-ellipsis">
11.3 Bubble sort
11.3 Bubble Sort
@@ -2838,7 +2838,7 @@
<span class="md-ellipsis">
11.4 Insertion sort
11.4 Insertion Sort
@@ -2866,7 +2866,7 @@
<span class="md-ellipsis">
11.5 Quick sort
11.5 Quick Sort
@@ -2894,7 +2894,7 @@
<span class="md-ellipsis">
11.6 Merge sort
11.6 Merge Sort
@@ -2922,7 +2922,7 @@
<span class="md-ellipsis">
11.7 Heap sort
11.7 Heap Sort
@@ -2950,7 +2950,7 @@
<span class="md-ellipsis">
11.8 Bucket sort
11.8 Bucket Sort
@@ -2978,7 +2978,7 @@
<span class="md-ellipsis">
11.9 Counting sort
11.9 Counting Sort
@@ -3006,7 +3006,7 @@
<span class="md-ellipsis">
11.10 Radix sort
11.10 Radix Sort
@@ -3101,7 +3101,7 @@
<span class="md-ellipsis">
Chapter 12. Divide and conquer
Chapter 12. Divide and Conquer
@@ -3123,7 +3123,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 12. Divide and conquer
Chapter 12. Divide and Conquer
</label>
@@ -3145,7 +3145,7 @@
<span class="md-ellipsis">
12.1 Divide and conquer algorithms
12.1 Divide and Conquer Algorithms
@@ -3173,7 +3173,7 @@
<span class="md-ellipsis">
12.2 Divide and conquer search strategy
12.2 Divide and Conquer Search Strategy
@@ -3201,7 +3201,7 @@
<span class="md-ellipsis">
12.3 Building binary tree problem
12.3 Building a Binary Tree Problem
@@ -3229,7 +3229,7 @@
<span class="md-ellipsis">
12.4 Tower of Hanoi Problem
12.4 Hanoi Tower Problem
@@ -3259,6 +3259,24 @@
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
12.5 Summary
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
@@ -3276,6 +3294,36 @@
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#1-key-review" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; Key Review
</span>
</a>
</li>
</ul>
</nav>
</li>
@@ -3376,7 +3424,7 @@
<span class="md-ellipsis">
13.1 Backtracking algorithms
13.1 Backtracking Algorithm
@@ -3404,7 +3452,7 @@
<span class="md-ellipsis">
13.2 Permutation problem
13.2 Permutations Problem
@@ -3432,7 +3480,7 @@
<span class="md-ellipsis">
13.3 Subset sum problem
13.3 Subset-Sum Problem
@@ -3460,7 +3508,7 @@
<span class="md-ellipsis">
13.4 n queens problem
13.4 N-Queens Problem
@@ -3557,7 +3605,7 @@
<span class="md-ellipsis">
Chapter 14. Dynamic programming
Chapter 14. Dynamic Programming
@@ -3579,7 +3627,7 @@
<span class="md-nav__icon md-icon"></span>
Chapter 14. Dynamic programming
Chapter 14. Dynamic Programming
</label>
@@ -3601,7 +3649,7 @@
<span class="md-ellipsis">
14.1 Introduction to dynamic programming
14.1 Introduction to Dynamic Programming
@@ -3629,7 +3677,7 @@
<span class="md-ellipsis">
14.2 Characteristics of DP problems
14.2 Characteristics of Dynamic Programming Problems
@@ -3657,7 +3705,7 @@
<span class="md-ellipsis">
14.3 DP problem-solving approach
14.3 Dynamic Programming Problem-Solving Approach
@@ -3685,7 +3733,7 @@
<span class="md-ellipsis">
14.4 0-1 Knapsack problem
14.4 0-1 Knapsack Problem
@@ -3713,7 +3761,7 @@
<span class="md-ellipsis">
14.5 Unbounded knapsack problem
14.5 Unbounded Knapsack Problem
@@ -3741,7 +3789,7 @@
<span class="md-ellipsis">
14.6 Edit distance problem
14.6 Edit Distance Problem
@@ -3878,7 +3926,7 @@
<span class="md-ellipsis">
15.1 Greedy algorithms
15.1 Greedy Algorithm
@@ -3906,7 +3954,7 @@
<span class="md-ellipsis">
15.2 Fractional knapsack problem
15.2 Fractional Knapsack Problem
@@ -3934,7 +3982,7 @@
<span class="md-ellipsis">
15.3 Maximum capacity problem
15.3 Maximum Capacity Problem
@@ -3962,7 +4010,7 @@
<span class="md-ellipsis">
15.4 Maximum product cutting problem
15.4 Maximum Product Cutting Problem
@@ -4095,7 +4143,7 @@
<span class="md-ellipsis">
16.1 Installation
16.1 Programming Environment Installation
@@ -4123,7 +4171,7 @@
<span class="md-ellipsis">
16.2 Contributing
16.2 Contributing Together
@@ -4151,7 +4199,7 @@
<span class="md-ellipsis">
16.3 Terminology
16.3 Terminology Table
@@ -4258,6 +4306,25 @@
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#1-key-review" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; Key Review
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
@@ -4294,16 +4361,17 @@
<!-- Page content -->
<h1 id="125-summary">12.5 &nbsp; Summary<a class="headerlink" href="#125-summary" title="Permanent link">&para;</a></h1>
<h3 id="1-key-review">1. &nbsp; Key Review<a class="headerlink" href="#1-key-review" title="Permanent link">&para;</a></h3>
<ul>
<li>Divide and conquer is a common algorithm design strategy that consists of two stages—divide (partition) and conquer (merge)—and is generally implemented using recursion.</li>
<li>To determine whether a problem is suited for a divide and conquer approach, we check if the problem can be decomposed, whether the subproblems are independent, and whether the subproblems can be merged.</li>
<li>Merge sort is a typical example of the divide and conquer strategy. It recursively splits an array into two equal-length subarrays until only one element remains, and then merges these subarrays layer by layer to complete the sorting.</li>
<li>Introducing the divide and conquer strategy often improves algorithm efficiency. On one hand, it reduces the number of operations; on the other hand, it facilitates parallel optimization of the system after division.</li>
<li>Divide and conquer can be applied to numerous algorithmic problems and is widely used in data structures and algorithm design, appearing in many scenarios.</li>
<li>Compared to brute force search, adaptive search is more efficient. Search algorithms with a time complexity of <span class="arithmatex">\(O(\log n)\)</span> are typically based on the divide and conquer strategy.</li>
<li>Binary search is another classic application of the divide-and-conquer strategy. It does not involve merging subproblem solutions and can be implemented via a recursive divide-and-conquer approach.</li>
<li>In the problem of constructing binary trees, building the tree (the original problem) can be divided into building the left subtree and right subtree (the subproblems). This can be achieved by partitioning the index ranges of the preorder and inorder traversals.</li>
<li>In the Tower of Hanoi problem, a problem of size <span class="arithmatex">\(n\)</span> can be broken down into two subproblems of size <span class="arithmatex">\(n-1\)</span> and one subproblem of size <span class="arithmatex">\(1\)</span>. By solving these three subproblems in sequence, the original problem is resolved.</li>
<li>Divide and conquer is a common algorithm design strategy, consisting of two phases: divide (partition) and conquer (merge), typically implemented based on recursion.</li>
<li>The criteria for determining whether a problem is a divide and conquer problem include: whether the problem can be decomposed, whether subproblems are independent, and whether subproblems can be merged.</li>
<li>Merge sort is a typical application of the divide and conquer strategy. It recursively divides an array into two equal-length subarrays until only one element remains, then merges them layer by layer to complete the sorting.</li>
<li>Introducing the divide and conquer strategy can often improve algorithm efficiency. On one hand, the divide and conquer strategy reduces the number of operations; on the other hand, it facilitates parallel optimization of the system after division.</li>
<li>Divide and conquer can both solve many algorithmic problems and is widely applied in data structure and algorithm design, appearing everywhere.</li>
<li>Compared to brute-force search, adaptive search is more efficient. Search algorithms with time complexity of <span class="arithmatex">\(O(\log n)\)</span> are typically implemented based on the divide and conquer strategy.</li>
<li>Binary search is another typical application of divide and conquer. It does not include the step of merging solutions of subproblems. We can implement binary search through recursive divide and conquer.</li>
<li>In the problem of building a binary tree, building the tree (original problem) can be divided into building the left subtree and right subtree (subproblems), which can be achieved by dividing the index intervals of the preorder and inorder traversals.</li>
<li>In the hanota problem, a problem of size <span class="arithmatex">\(n\)</span> can be divided into two subproblems of size <span class="arithmatex">\(n-1\)</span> and one subproblem of size <span class="arithmatex">\(1\)</span>. After solving these three subproblems in order, the original problem is solved.</li>
</ul>
<!-- Source file information -->
@@ -4327,7 +4395,7 @@ aria-label="Footer"
<a
href="../hanota_problem/"
class="md-footer__link md-footer__link--prev"
aria-label="Previous: 12.4 Tower of Hanoi Problem"
aria-label="Previous: 12.4 Hanoi Tower Problem"
rel="prev"
>
<div class="md-footer__button md-icon">
@@ -4339,7 +4407,7 @@ aria-label="Footer"
Previous
</span>
<div class="md-ellipsis">
12.4 Tower of Hanoi Problem
12.4 Hanoi Tower Problem
</div>
</div>
</a>
@@ -4452,7 +4520,7 @@ aria-label="Footer"
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../hanota_problem/" class="md-footer__link md-footer__link--prev" aria-label="Previous: 12.4 Tower of Hanoi Problem">
<a href="../hanota_problem/" class="md-footer__link md-footer__link--prev" aria-label="Previous: 12.4 Hanoi Tower Problem">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
@@ -4462,7 +4530,7 @@ aria-label="Footer"
Previous
</span>
<div class="md-ellipsis">
12.4 Tower of Hanoi Problem
12.4 Hanoi Tower Problem
</div>
</div>
</a>