Facebook Pixel

Binary Search and Monotonic Function

In the preceding binary search problems, the arrays are always sorted. We stated that we can use binary search whenever we make a binary decision to shrink the search range. This might sound a little abstract. In this module, we will dive a little further into when we can use binary search.

Monotonic Function

monotonic function

A monotonic function is a function that is either non-decreasing or non-increasing. Given x1 and x2 where x1 > x2, we should have f(x1) >= f(x2).

A sorted array is monotonic because the value increases or stays the same as the index increases.

If f(x) only contains Boolean values True and False and we think of true as 1 and false as 0, then a sorted Boolean array would consist of consecutive 0s and then consecutive 1s. For example, FFFFTTTTT.

Binary Search Template

feasible function

The precondition for binary search is to find a monotonic function f(x) that returns either True or False. Then the problem becomes Find the First True in a Sorted Boolean Array that we already know how to solve using binary search. We will call the function feasible to signify whether the element at the current index is feasible (True) or not (False) to meet the problem constraints.

Binary Search Template Monotonic Feasibility Function

1def binary_search(arr: List[int], target: int) -> int:
2    left, right = 0, len(arr) - 1
3    first_true_index = -1
4    while left <= right:
5        mid = (left + right) // 2
6        if feasible(mid):
7            first_true_index = mid
8            right = mid - 1
9        else:
10            left = mid + 1
11
12    return first_true_index
13
1public static int binarySearch(List<Integer> arr, int target) {
2    int left = 0;
3    int right = arr.size() - 1;
4    int firstTrueIndex = -1;
5    while (left <= right) {
6        int mid = left + (right - left) / 2;
7        if (feasible(mid)) {
8            firstTrueIndex = mid;
9            right = mid - 1;
10        } else {
11            left = mid + 1;
12        }
13    }
14    return firstTrueIndex;
15}
16
1public static int BinarySearch(List<int> arr, int target)
2{
3    int left = 0;
4    int right = arr.Count - 1;
5    int firstTrueIndex = -1;
6    while (left <= right)
7    {
8        int mid = (left + right) / 2;
9        if (feasible(mid))
10        {
11            firstTrueIndex = mid;
12            right = mid - 1;
13        }
14        else
15        {
16            left = mid + 1;
17        }
18    }
19    return firstTrueIndex;
20}
21
1function binarySearch(arr, target) {
2    let left = 0;
3    let right = arr.length - 1;
4    let first_true_index = -1;
5
6    while (left <= right) {
7        let mid = Math.floor((left + right) / 2);
8        if (feasible(mid)) {
9            first_true_index = mid;
10            right = mid - 1;
11        } else {
12            left = mid + 1;
13        }
14    }
15    return first_true_index;
16}
17
1function binarySearch(arr: number[], target: number): number {
2    let left = 0;
3    let right = arr.length - 1;
4    let first_true_index = -1;
5
6    while (left <= right) {
7        let mid = Math.floor((left + right) / 2);
8        if (feasible(mid)) {
9            first_true_index = mid;
10            right = mid - 1;
11        } else {
12            left = mid + 1;
13        }
14    }
15    return first_true_index;
16}
17
1int binary_search(std::vector<int> arr, int target) {
2    int left = 0;
3    int right = arr.size() - 1;
4    int firstTrueIndex = -1;
5    while (left <= right) {
6        int mid = left + (right - left) / 2;
7        if (feasible(mid)) {
8            firstTrueIndex = mid;
9            right = mid - 1;
10        } else {
11            left = mid + 1;
12        }
13    }
14    return firstTrueIndex;
15}
16
1func binarySearch(arr []int, target int) int {
2    left := 0
3    right := len(arr) - 1
4    firstTrueIndex := -1
5    for left <= right {
6        mid := (left + right) / 2
7        if feasible(mid) {
8            firstTrueIndex = mid
9            right = mid - 1
10        } else {
11            left = mid + 1
12        }
13    }
14    return firstTrueIndex
15}
16
1fn binary_search(arr: &[i32], target: i32) -> i32 {
2    let mut left = 0i32;
3    let mut right = arr.len() as i32 - 1;
4    let mut first_true_index = -1;
5    while left <= right {
6        let mid = left + (right - left) / 2;
7        if feasible(mid) {
8            first_true_index = mid;
9            right = mid - 1;
10        } else {
11            left = mid + 1;
12        }
13    }
14    first_true_index
15}
16
1def binary_search(arr, target)
2    left = 0
3    right = arr.length - 1
4    first_true_index = -1
5    while left <= right
6        mid = (left + right) / 2
7        if feasible(mid)
8            first_true_index = mid
9            right = mid - 1
10        else
11            left = mid + 1
12        end
13    end
14    first_true_index
15end
16
1(define (binary-search arr target)
2  (let loop ([left 0]
3             [right (sub1 (vector-length arr))]
4             [first-true-index -1])
5    (if (<= left right)
6        (let ([mid (quotient (+ left right) 2)])
7          (if (feasible mid)
8              (loop left (sub1 mid) mid)
9              (loop (add1 mid) right first-true-index)))
10        first-true-index)))
11
1binarySearch :: [Int] -> Int -> Int
2binarySearch arr target = search 0 (length arr - 1) (-1)
3  where
4    search left right firstTrueIndex
5        | left <= right =
6            let mid = left + (right - left) `div` 2
7            in if feasible mid
8               then search left (mid - 1) mid
9               else search (mid + 1) right firstTrueIndex
10        | otherwise = firstTrueIndex
11

Now, the problem has become finding the feasible function and then mechanically applying the template.

In the Find the First True in a Sorted Boolean Array problem, the feasible function is simply arr[mid] == True. Finding the feasible function can be trickier in other problems. Let's look at a few examples.

Invest in Yourself
Your new job is waiting. 83% of people that complete the program get a job offer. Unlock unlimited access to all content and features.
Go Pro