mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-23 16:47:13 +00:00
deploy
This commit is contained in:
@@ -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 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 ></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 Two types of interval definitions </p>
|
||||
|
||||
@@ -3848,7 +3848,7 @@
|
||||
<p>Below we introduce two more cunning methods.</p>
|
||||
<h3 id="1-reusing-the-search-for-the-left-boundary">1. Reusing the search for the left boundary<a class="headerlink" href="#1-reusing-the-search-for-the-left-boundary" title="Permanent link">¶</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 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. Transforming into an element search<a class="headerlink" href="#2-transforming-into-an-element-search" title="Permanent link">¶</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>
|
||||
|
||||
@@ -3595,7 +3595,7 @@
|
||||
<h2 id="1021-case-with-no-duplicate-elements">10.2.1 Case with no duplicate elements<a class="headerlink" href="#1021-case-with-no-duplicate-elements" title="Permanent link">¶</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 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 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] < target</code> or <code>nums[m] > 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>
|
||||
|
||||
@@ -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 Linear search: trading time for space<a class="headerlink" href="#1041-linear-search-trading-time-for-space" title="Permanent link">¶</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 Linear search solution for two-sum problem </p>
|
||||
|
||||
|
||||
@@ -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 Choosing a search method<a class="headerlink" href="#1053-choosing-a-search-method" title="Permanent link">¶</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 Various search strategies </p>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user