Skip to content

Binary Search Topics

Binary Search Forms:

Ordinary search (exact match)

python
def binary_search_exact(nums, target):
    left, right = 0, len(nums)-1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid-1
    return -1

assert binary_search_exact([1,2,3], 2) == 1

Find first occurrence of element in sorted array (left most match)

Exact match

python
def binary_search_left(nums, target):
    left, right = 0, len(nums)-1
    while left <= right:
        mid = (left+right) // 2
        if nums[mid] == target:
            if (mid == 0 or target > nums[mid-1]):
                return mid
            else: # found match, but not the first one, so do don't stop searching
                # shrink right boundary (towards left) to find first occurrence
                right = mid - 1
        elif target > nums[mid]:
            left = mid + 1
        else:
            right = mid - 1
    return -1

assert binary_search_left([1,2,2,2,3], 2) == 1

Alternative (bisect left)

python
def binary_search_left(nums, target):
    left, right = 0, len(nums)
    while left < right:
        mid = (left + right) // 2
        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid
    return left
assert binary_search_left([1,2,2,2,3], 2) == 1

Find last occurrence of element in sorted array (right most match)

Exact match

python
def binary_search_right(nums, target):
    left, right = 0, len(nums)-1
    while left <= right:
        mid = (left+right) // 2
        if nums[mid] == target:
            if  (mid == len(nums)-1 or nums[mid+1] > target):
                return mid
            else: # found match, but not the last one, so do don't stop searching
                # shrink left boundary (towards right) to find last occurrence
                left = mid + 1
        elif target > nums[mid]:
            left = mid + 1
        else:
            right = mid - 1
    return -1

assert binary_search_right([1,2,2,2,3], 2) == 3

Alternative (bisect right)

python
def binary_search_right(nums, target):
    left, right = 0, len(nums)
    while left < right:
        mid = (left + right) // 2
        if a[mid] > target:
            right = mid
        else:
            left = mid + 1
    return left
assert binary_search_right([1,2,2,2,3], 2) == 4

Find median of two sorted arrays

You are given two integer arrays nums1 and nums2 of size m and n respectively, where each is sorted in ascending order. Return the median value among all elements of the two arrays.

Your solution must run in O(log(m+n)) time.

  • Binary Search Approach:

    • aim to partition both arrays such that the left partition contains half of the total elements (rounded down if the total number is odd).
    • We need to ensure that all elements in the left partition are less than or equal to all elements in the right partition.
  • Partitioning:

    • Let x be the number of elements in nums1 and y be the number of elements in nums2.
    • We need to find a partition such that the number of elements on the left side is (x + y + 1) // 2 (this ensures that if the total number of elements is odd, the left partition has one more element).
  • Finding the Correct Partition:

    • Use binary search to find the correct partition in nums1.

    • For each partition in nums1, calculate the corresponding partition in nums2.

    • Check if the partition is correct by comparing the maximum element on the left side with the minimum element on the right side.

python
class Solution:
    """
    Find the median of two sorted arrays.

    :param nums1: The first sorted array
    :param nums2: The second sorted array
    :return: The median of two sorted arrays
    """
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        # Make sure nums2 is the longer array
        if len(nums2) < len(nums1):
            nums1, nums2 = nums2, nums1

        m, n = len(nums1), len(nums2) # m < n
        total = m+n
        half = (m+n) // 2

        # search in nums1 array only
        l, r = 0, m-1
        while True:
            i = (l+r) // 2 # i is index of end of left partition, left has i+1 elements
            j = half - i - 2 # half-i-1 is number of left partitions in nums2, half-i-2 is the index of end of left partition

            # Calculate the value of the elements at the boundary of the two partitions
            left1 = nums1[i] if i >= 0 else float('-inf')
            right1 = nums1[i+1] if i+1 < m else float('inf')
            left2 = nums2[j] if j >= 0 else float('-inf')
            right2 = nums2[j+1] if j+1 < n else float('inf')

            # Check whether the current partition is correct
            if left1 <= right2 and left2 <= right1:
                if total % 2 == 0:
                    # If the total number of elements is even, return the average
                    return (max(left1, left2) + min(right1, right2)) / 2
                else:
                    # If the total number of elements is odd, return the smaller one
                    return min(right1, right2)

            # If the left partition is larger, move the right pointer to the left
            elif left1 > right2:
                r = i-1
            # If the left partition is smaller, move the left pointer to the right
            else:
                l = i+1