Compare commits

..

2 commits

Author SHA1 Message Date
yanedie
46df025ff7
Merge ed17b6f918 into dad0a3fd95 2024-12-06 13:38:42 +00:00
yanedie
ed17b6f918 Fix typos and clarify binary search edge cases 2024-12-06 21:38:22 +08:00
2 changed files with 10 additions and 10 deletions

View file

@ -6,7 +6,7 @@
Given a sorted array `nums` of length $n$, which may contain duplicate elements, return the index of the leftmost element `target`. If the element is not present in the array, return $-1$.
Look back on the method of binary search for an insertion point, after the search is completed, the index $i$ will point to the leftmost occurrence of `target`. Therefore, **searching for the insertion point is essentially the same as finding the index of the leftmost `target`**.
Recall the method of binary search for an insertion point, after the search is completed, the index $i$ will point to the leftmost occurrence of `target`. Therefore, **searching for the insertion point is essentially the same as finding the index of the leftmost `target`**.
We can use the function for finding an insertion point to find the left boundary of `target`. Note that the array might not contain `target`, which could lead to the following two results:
@ -29,7 +29,7 @@ Below we are going to introduce two more ingenious methods.
To find the rightmost occurrence of `target`, we can reuse the logic for finding the leftmost occurrence of `target`. Specifically, we can find the leftmost `target`, and then adjust the result to point to the rightmost `target` by simply adding 1 to the index of the leftmost `target`.
As shown in the figure below, after the search is complete, pointer $i$ will point to the the position just after the leftmost `target` (i.e., `target + 1`), and pointer $j$ will point to the rightmost `target`. Therefore, returning $j$ will give us the right boundary.
As shown in the figure below, after the search is complete, pointer $i$ will point to the position just after the leftmost `target` (i.e., `target + 1`), and pointer $j$ will point to the rightmost `target`. Therefore, returning $j$ will give us the right boundary.
![Transforming the search for the right boundary into the search for the left boundary](binary_search_edge.assets/binary_search_right_edge_by_left_edge.png)
@ -52,5 +52,5 @@ Thus, as shown in the figure below, we can construct an element that does not ex
The code is omitted here, but here are two important points to note about this approach.
- Since the given array does not contain decimals, this means we do not need to worry about handling equal cases.
- Because this method introduces decimals, the variable `target` in the function needs to be changed to a floating point type (no change needed in Python).
- The given array `nums` does not contain decimal, so handling equal cases is not a concern.
- However, the introduction of decimal in this approach requires modifying the `target` variable to a floating-point type (no change needed in Python).

View file

@ -36,17 +36,17 @@ When there are multiple occurrences of `target` in the array, a regular binary s
The problem requires inserting the target element to the very left, **so we need to find the index of the leftmost `target` in the array**. Initially consider implementing this through the steps shown in the figure below.
1. Perform a binary search to find any `target`'s index, say $k$.
2. Starting from index $k$, perform a linear search to the left until the leftmost `target` is found and return.
1. Perform a binary search to find any index of `target`, say $k$.
2. Starting from index $k$, conduct a linear traversal to the left until the leftmost occurrence of `target` is found, then return this index.
![Linear search for the insertion point of duplicate elements](binary_search_insertion.assets/binary_search_insertion_naive.png)
Although this method is feasible, it includes linear search, so its time complexity is $O(n)$. This method is inefficient when the array contains many duplicate `target`s.
Now consider extending the binary search code. As shown in the figure below, the overall process remains the same. In each round, we first calculate the middle index $m$, then compare the value of `target` and `nums[m]`, which results in the following cases.
Now consider extending the binary search code. As shown in the figure below, the overall process remains the same. In each round, we first calculate the middle index $m$, then compare the value of `target` with `nums[m]`, which results in the following cases.
- When `nums[m] < target` or `nums[m] > target`, it means `target` has not been found yet, thus use the normal binary search to narrow the search range, **bring the pointers $i$ and $j$ closer to `target`**.
- When `nums[m] == target`, it indicates that the elements less than `target` are in the range $[i, m - 1]$, therefore use $j = m - 1$ to narrow the range, **thus making pointer $j$ closer to the elements less than `target`**.
- When `nums[m] < target` or `nums[m] > target`, it means `target` has not been found yet, thus use the normal binary search to narrow the search range, **bring pointers $i$ and $j$ closer to `target`**.
- When `nums[m] == target`, it indicates that the elements less than `target` are in the range $[i, m - 1]$, therefore use $j = m - 1$ to narrow the range, **thus bring pointer $j$ closer to the elements less than `target`**.
After the loop, $i$ points to the leftmost `target`, and $j$ points to the first element less than `target`, **therefore index $i$ is the insertion point**.
@ -88,4 +88,4 @@ Even so, we can still keep the conditions expanded, as it makes the logic cleare
In summary, binary search essentially involves setting search targets for pointers $i$ and $j$, which might be a specific element (like `target`) or a range of elements (like elements less than `target`).
In the continuous loop of binary search, pointers $i$ and $j$ gradually approach the predefined target. In the end, they either find the answer or stop after crossing the boundary.
In the continuous loop of binary search, pointers $i$ and $j$ gradually approach the predefined target. Ultimately, they either find the answer or stop after crossing the boundary.