This is a common variation of a binary search, and is often used in binary search-related problems.
Problem
An array of boolean values is divided into two sections; the left section consists of all false
and the right section consists of all true
. Find the First True in a Sorted Boolean Array of the right section, i.e. the index of the first true
element. If there is no true
element, return -1.
Solution
- Time complexity
- Space complexity
Here, we update l
and r
just like a numerical binary search. For the right case there’s a difference:
- If the current element is
true
, the current element could be the firsttrue
although there may be othertrue
to the left. - Thus, after we discard everything to the right (by updating
r
) and store the current element.
Alternate Solution
Another approach to handle the right side case above is to keep the current element in the search range instead of discarding it, doing if arr[mid]: right = mid
instead of right = mid - 1
.
- However, doing this without modifying the
while
condition will result in an infinite loop. This is because whenleft == right
,right = mid
will not modifyright
. So, the search range doesn’t shrink and we will be stuck in the while loop forever. - To make this work, we have to remove the equality in the
while
condition. In addition, as mentioned in the last module, awhile
loop without equality will miss the single-element edge case so we have to add an additional check after the loop to handle this case. - Overall, we have to make three modifications to the vanilla binary search to make it work.
Using with “feasible”
To use binary search, we must be dealing with some monotonic function – in this case, a monotonic function that either returns True
or False
. We can design a feasible
function to signify whether the element at the current index is feasible (True
) or not (False
) to meet the problem constraints.
Example: First Element Not Smaller Than Target
Given an array of integers sorted in increasing order and a target, find the index of the first element in the array that is larger than or equal to the target. Assume that it is guaranteed to find a satisfying number.
- Input:
arr = [1, 3, 3, 5, 8, 8, 10]
target = 2
- Output:
1
The problem is equivalent to finding the boundary of elements less than 2 and elements larger than or equal to 2 in the sorted array. Because the array is sorted, as the index increases, once we see an element greater than 2, the rest of the array should also be greater than 2. This is a monotonic function. The feasible
function here is arr[i] >= target
.
This is the exact same as binary search for boolean array, except we changed the condition to arr[mid] >= target
.
Example: Find Element in Sorted Array with Duplicates
Given a sorted array of integers and a target integer, find the first occurrence of the target and return its index. Return -1 if the target is not in the array.
- Input:
arr = [1, 3, 3, 3, 3, 6, 10, 10, 10, 100]
target = 3
- Output:
1
The feasible function is arr[i] >= target
. However, the question wants the index of the first element exactly equal to the target.
- Our template updates
ans = mid
wheneverarr[mid] >= target
. - Therefore we have to make a small modification to the template and move
ans = mid
to only whenarr[mid] == target
and notarr[mid] >= target
.