Finding Boundary with Binary Search

Prereq: Binary Search Introduction

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 boundary of the right section, i.e. index of the first true element. If there is no true element, return -1.

Input: arr = [false, false, true, true, true]

Output: 2

Explanation: first true's index is 2.

Try it yourself

Explanation

The binary decision we have to make when we look at an element is

  1. if the element is false, we discard everything to the left and the current element itself.
  2. if the element is true, the current element could be the first true although they may be other true to the left. We discard everything to the right but what about the current element?

We can either keep the current element in the range or record it somewhere and then discard it. Here we choose the latter. We'll discuss the other approach in the alternative solution section.

We keep a variable boundary_index that represents the leftmost true's index we currently have. If the current element is true, then we update boundary_index with its index and discard everything to the right including the current element itself since its index has been recorded by the variable.

Implemetation

1
1
from typing import List
2
2
3
3
def find_boundary(arr: List[bool]) -> int:
4
-
    # WRITE YOUR BRILLIANT CODE HERE
4
+
    left, right = 0, len(arr) - 1
5
+
    boundary_index = -1
6
+
    while left <= right:
7
+
        mid = (left + right) // 2
8
+
        if arr[mid]:
9
+
            boundary_index = mid
10
+
            right = mid - 1
11
+
        else:
12
+
            left = mid + 1
13
+
14
+
    return boundary_index
15
+
5
16
if __name__ == '__main__':
6
17
    arr = [x == "true" for x in input().split()]
7
18
    res = find_boundary(arr)
8
19
    print(res)

The good thing with this approach is we don't have to modify the while loop logic in vanilla binary search from the last module besides introducing a variable.


Alternative approach

Another approach to handle case 2 above is to keep the current element in the search range instead of discarding it, i.e. 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 when left == right, right = mid will not modify right and thus not shrink search range and we are 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, while 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.

Side note: how to not stuck in an infinite loop

  • make progress in each step
  • have an exit strategy

Summary

This problem is major 🔑 in solving future binary search-related problems. As we will see in the following modules, many problems boil down to finding the boundary in a boolean array.