Revisit the English version (#1835)

* Review the English version using Claude-4.5.

* Update mkdocs.yml

* Align the section titles.

* Bug fixes
This commit is contained in:
Yudong Jin
2025-12-30 17:54:01 +08:00
committed by GitHub
parent 091afd38b4
commit 45e1295241
106 changed files with 4195 additions and 3398 deletions
+24 -24
View File
@@ -1,56 +1,56 @@
# Binary search boundaries
# Binary search edge cases
## Find the left boundary
## Finding the left boundary
!!! question
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$.
Given a sorted array `nums` of length $n$ that may contain duplicate elements, return the index of the leftmost element `target` in the array. If the array does not contain the element, return $-1$.
Recalling 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 for finding the insertion point with binary search. After the search completes, $i$ points to the leftmost `target`, **so finding the insertion point is essentially 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:
Consider implementing the left boundary search using the insertion point finding function. Note that the array may not contain `target`, which could result in the following two cases:
- The index $i$ of the insertion point is out of bounds.
- The insertion point index $i$ is out of bounds.
- The element `nums[i]` is not equal to `target`.
In these cases, simply return $-1$. The code is as follows:
When either of these situations occurs, simply return $-1$. The code is shown below:
```src
[file]{binary_search_edge}-[class]{}-[func]{binary_search_left_edge}
```
## Find the right boundary
## Finding the right boundary
How do we find the rightmost occurrence of `target`? The most straightforward way is to modify the traditional binary search logic by changing how we adjust the search boundaries in the case of `nums[m] == target`. The code is omitted here. If you are interested, try to implement the code on your own.
So how do we find the rightmost `target`? The most direct approach is to modify the code and replace the pointer shrinking operation in the `nums[m] == target` case. The code is omitted here; interested readers can implement it themselves.
Below we are going to introduce two more ingenious methods.
Below we introduce two more clever methods.
### Reuse the left boundary search
### Reusing left boundary search
To find the rightmost occurrence of `target`, we can reuse the function used for locating the leftmost `target`. Specifically, we transform the search for the rightmost target into a search for the leftmost target + 1.
In fact, we can use the function for finding the leftmost element to find the rightmost element. The specific method is: **Convert finding the rightmost `target` into finding the leftmost `target + 1`**.
As shown in the figure below, after the search is complete, pointer $i$ will point to the leftmost `target + 1` (if exists), while pointer $j$ will point to the rightmost occurrence of `target`. Therefore, returning $j$ will give us the right boundary.
As shown in the figure below, after the search completes, pointer $i$ points to the leftmost `target + 1` (if it exists), while $j$ points to the rightmost `target`, **so we can simply return $j$**.
![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)
![Converting right boundary search to left boundary search](binary_search_edge.assets/binary_search_right_edge_by_left_edge.png)
Note that the insertion point returned is $i$, therefore, it should be subtracted by $1$ to obtain $j$:
Note that the returned insertion point is $i$, so we need to subtract $1$ from it to obtain $j$:
```src
[file]{binary_search_edge}-[class]{}-[func]{binary_search_right_edge}
```
### Transform into an element search
### Converting to element search
When the array does not contain `target`, $i$ and $j$ will eventually point to the first element greater and smaller than `target` respectively.
We know that when the array does not contain `target`, $i$ and $j$ will eventually point to the first elements greater than and less than `target`, respectively.
Thus, as shown in the figure below, we can construct an element that does not exist in the array, to search for the left and right boundaries.
Therefore, as shown in the figure below, we can construct an element that does not exist in the array to find the left and right boundaries.
- To find the leftmost `target`: it can be transformed into searching for `target - 0.5`, and return the pointer $i$.
- To find the rightmost `target`: it can be transformed into searching for `target + 0.5`, and return the pointer $j$.
- Finding the leftmost `target`: Can be converted to finding `target - 0.5` and returning pointer $i$.
- Finding the rightmost `target`: Can be converted to finding `target + 0.5` and returning pointer $j$.
![Transforming the search for boundaries into the search for an element](binary_search_edge.assets/binary_search_edge_by_element.png)
![Converting boundary search to element search](binary_search_edge.assets/binary_search_edge_by_element.png)
The code is omitted here, but here are two important points to note about this approach.
The code is omitted here, but the following two points are worth noting:
- The given array `nums` does not contain decimal, so handling equal cases is not a concern.
- However, introducing decimals in this approach requires modifying the `target` variable to a floating-point type (no change needed in Python).
- Since the given array does not contain decimals, we don't need to worry about how to handle equal cases.
- Because this method introduces decimals, the variable `target` in the function needs to be changed to a floating-point type (Python does not require this change).