mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-29 03:17:13 +00:00
deploy
This commit is contained in:
@@ -3588,17 +3588,17 @@
|
||||
<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 Figure 10-4.</p>
|
||||
<p>Given a sorted array <code>nums</code> of length <span class="arithmatex">\(n\)</span> with unique elements and an element <code>target</code>, insert <code>target</code> into <code>nums</code> while maintaining its sorted order. If <code>target</code> already exists in the array, insert it to the left of the existing element. 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>
|
||||
|
||||
<p>If you want to reuse the binary search code from the previous section, you need to answer the following two questions.</p>
|
||||
<p><strong>Question one</strong>: When the array contains <code>target</code>, is the insertion point index the index of that element?</p>
|
||||
<p>The requirement to insert <code>target</code> to the left of equal elements means that the newly inserted <code>target</code> replaces the original <code>target</code> position. Thus, <strong>when the array contains <code>target</code>, the insertion point index is the index of that <code>target</code></strong>.</p>
|
||||
<p><strong>Question two</strong>: When the array does not contain <code>target</code>, what is the index of the insertion point?</p>
|
||||
<p>Further consider the binary search process: when <code>nums[m] < target</code>, pointer <span class="arithmatex">\(i\)</span> moves, meaning that pointer <span class="arithmatex">\(i\)</span> is approaching an element greater than or equal to <code>target</code>. Similarly, pointer <span class="arithmatex">\(j\)</span> is always approaching an element less than or equal to <code>target</code>.</p>
|
||||
<p>Therefore, at the end of the binary, it is certain that: <span class="arithmatex">\(i\)</span> points to the first element greater than <code>target</code>, and <span class="arithmatex">\(j\)</span> points to the first element less than <code>target</code>. <strong>It is easy to see that when the array does not contain <code>target</code>, the insertion index is <span class="arithmatex">\(i\)</span></strong>. The code is as follows:</p>
|
||||
<p><strong>Question one</strong>: If the array already contains <code>target</code>, would the insertion point be the index of existing element?</p>
|
||||
<p>The requirement to insert <code>target</code> to the left of equal elements means that the newly inserted <code>target</code> will replace the original <code>target</code> position. In other words, <strong>when the array contains <code>target</code>, the insertion point is indeed the index of that <code>target</code></strong>.</p>
|
||||
<p><strong>Question two</strong>: When the array does not contain <code>target</code>, at which index would it be inserted?</p>
|
||||
<p>Let's further consider the binary search process: when <code>nums[m] < target</code>, pointer <span class="arithmatex">\(i\)</span> moves, meaning that pointer <span class="arithmatex">\(i\)</span> is approaching an element greater than or equal to <code>target</code>. Similarly, pointer <span class="arithmatex">\(j\)</span> is always approaching an element less than or equal to <code>target</code>.</p>
|
||||
<p>Therefore, at the end of the binary, it is certain that: <span class="arithmatex">\(i\)</span> points to the first element greater than <code>target</code>, and <span class="arithmatex">\(j\)</span> points to the first element less than <code>target</code>. <strong>It is easy to see that when the array does not contain <code>target</code>, the insertion point is <span class="arithmatex">\(i\)</span></strong>. The 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">
|
||||
@@ -3706,20 +3706,20 @@
|
||||
<p class="admonition-title">Question</p>
|
||||
<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 Figure 10-5.</p>
|
||||
<p>When there are multiple occurrences of <code>target</code> in the array, a regular binary search can only return the index of one occurrence of <code>target</code>, <strong>and it cannot determine how many occurrences of <code>target</code> are to the left and right of that position</strong>.</p>
|
||||
<p>The problem requires inserting the target element at the leftmost position, <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>
|
||||
<li>Perform a binary search to find any index of <code>target</code>, say <span class="arithmatex">\(k\)</span>.</li>
|
||||
<li>Starting from index <span class="arithmatex">\(k\)</span>, conduct a linear search to the left until the leftmost occurrence of <code>target</code> is found, then return this index.</li>
|
||||
</ol>
|
||||
<p><a class="glightbox" href="../binary_search_insertion.assets/binary_search_insertion_naive.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Linear search for the insertion point of duplicate elements" class="animation-figure" src="../binary_search_insertion.assets/binary_search_insertion_naive.png" /></a></p>
|
||||
<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 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. In each round, we first calculate the middle index <span class="arithmatex">\(m\)</span>, then compare the value of <code>target</code> with <code>nums[m]</code>, leading to 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>
|
||||
<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 to narrow the search range, <strong>bringing pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span> closer to <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 range <span class="arithmatex">\([i, m - 1]\)</span>, therefore use <span class="arithmatex">\(j = m - 1\)</span> to narrow the range, <strong>thus bringing pointer <span class="arithmatex">\(j\)</span> closer to the elements less than <code>target</code></strong>.</li>
|
||||
</ul>
|
||||
<p>After the loop, <span class="arithmatex">\(i\)</span> points to the leftmost <code>target</code>, and <span class="arithmatex">\(j\)</span> points to the first element less than <code>target</code>, <strong>therefore index <span class="arithmatex">\(i\)</span> is the insertion point</strong>.</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:8"><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" /><div class="tabbed-labels"><label for="__tabbed_2_1"><1></label><label for="__tabbed_2_2"><2></label><label for="__tabbed_2_3"><3></label><label for="__tabbed_2_4"><4></label><label for="__tabbed_2_5"><5></label><label for="__tabbed_2_6"><6></label><label for="__tabbed_2_7"><7></label><label for="__tabbed_2_8"><8></label></div>
|
||||
@@ -3752,8 +3752,8 @@
|
||||
</div>
|
||||
<p align="center"> Figure 10-6 Steps for binary search insertion point of duplicate elements </p>
|
||||
|
||||
<p>Observe the code, the operations of the branch <code>nums[m] > target</code> and <code>nums[m] == target</code> are the same, so the two can be combined.</p>
|
||||
<p>Even so, we can still keep the conditions expanded, as their logic is clearer and more readable.</p>
|
||||
<p>Observe the following code. The operations in the branches <code>nums[m] > target</code> and <code>nums[m] == target</code> are the same, so these two branches can be merged.</p>
|
||||
<p>Even so, we can still keep the conditions expanded, as it makes the logic clearer and improves readability.</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">
|
||||
@@ -3858,9 +3858,9 @@
|
||||
</div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>The code in this section uses "closed intervals". Readers interested can implement the "left-closed right-open" method themselves.</p>
|
||||
<p>The code in this section uses "closed interval". If you are interested in "left-closed, right-open", try to implement the code on your own.</p>
|
||||
</div>
|
||||
<p>In summary, binary search is merely about setting search targets for pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span>, which might be a specific element (like <code>target</code>) or a range of elements (like elements less than <code>target</code>).</p>
|
||||
<p>In summary, binary search essentially involves setting search targets for pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span>. These targets could be a specific element (like <code>target</code>) or a range of elements (such as those smaller than <code>target</code>).</p>
|
||||
<p>In the continuous loop of binary search, pointers <span class="arithmatex">\(i\)</span> and <span class="arithmatex">\(j\)</span> gradually approach the predefined target. Ultimately, they either find the answer or stop after crossing the boundary.</p>
|
||||
|
||||
<!-- Source file information -->
|
||||
|
||||
Reference in New Issue
Block a user