Last true binary search finds the last index where a monotone Boolean predicate is true. It is the mirror form of first true binary search.
The predicate must have the form:
Once the predicate becomes false, it must remain false.
Problem
Given indices from to and a predicate , find the largest index such that
If no such index exists, return .
Key Idea
Maintain a half-open interval where the answer may exist. Test the midpoint, but bias the update toward the right side when the predicate is true.
If is true, then is a valid answer, and the last true position may be at or to its right. If is false, the answer must be to the left.
Algorithm
last_true(n, P):
l = 0
r = n
while l < r:
m = l + (r - l) // 2
if P(m):
l = m + 1
else:
r = m
return l - 1Example
Let the predicate values be:
| index | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| P(i) | true | true | true | true | false | false |
The last true index is .
The algorithm returns .
Relation to Upper Bound
If a sorted array is searched for the last element satisfying
then the predicate is true first and false later. Last true search returns the last index whose value is at most .
Equivalently:
Correctness
The algorithm maintains this invariant:
- All indices before have already been accepted as true candidates.
- All indices from onward have already been rejected or lie after the transition.
- The transition from true to false lies inside .
When is true, monotonicity implies that every index before is also true, so the last true index must be at or to the right. The algorithm moves to .
When is false, monotonicity implies that every index after is also false, so the last true index must be to the left. The algorithm moves to .
When the loop terminates, is the first false index. Therefore the last true index is .
Complexity
| cost | value |
|---|---|
| predicate evaluations | |
| time | |
| space |
Here is the cost of evaluating the predicate.
Use Cases
- Last valid prefix length
- Last index with value
- Maximum feasible answer
- Last successful test case
- Right boundary of a sorted range
Implementation
def last_true(n, pred):
l, r = 0, n
while l < r:
m = l + (r - l) // 2
if pred(m):
l = m + 1
else:
r = m
return l - 1func LastTrue(n int, pred func(int) bool) int {
l, r := 0, n
for l < r {
m := l + (r-l)/2
if pred(m) {
l = m + 1
} else {
r = m
}
}
return l - 1
}