First and Last Position
Duplicates turn the search into a boundary problem
In a sorted array, equal values stand next to one another. Therefore all occurrences of target
form one continuous range. Its beginning can be found with lower bound, and its end with upper bound.
static int[] firstAndLast(int[] values, int target) {
int first = lowerBound(values, target);
if (first == values.length || values[first] != target) {
return new int[] {-1, -1};
}
int last = upperBound(values, target) - 1;
return new int[] {first, last};
}
First, we find the first position whose value is not less than the target. If that position is outside the array or contains a different value,
then target is absent. Otherwise, the first index is already known.
Why upper bound is decreased by one
Upper bound points to the first position whose value is greater than the target. Therefore,
the last occurrence of target is immediately before that boundary.
That is why the expression upperBound(values, target) - 1 is used.
The complexity does not change
We run two binary searches, each taking O(log n). The total is still O(log n), because a constant number of logarithmic passes does not change the asymptotic complexity.