Reference: Link

LeetCode Binary Search Summary 二分搜索法小结

I think most of CSE students are very familiar with binary search. But you may see so many versions of binary search. We need to be careful about the target value, left/low value and right/high value. There are three main kinds of binary search.

  1. Find the value which is equal to the target value. This is the most common one. Here is the code.

     int find(int[] nums, int target) {
         int left = 0, right = nums.length-1;
         while (left <= right) {
             int mid = left + (right - left) / 2;
             if (nums[mid] == target) return mid;
             else if (nums[mid] < target) left = mid + 1;
             else right = mid-1;
         }
         return -1;
     }
    

Leetcode problem: Intersection of Two Arrays.

  1. Find the first value which is not smaller than the target value/ the last value which is smaller than the target value. For this version, the target value maybe not in the array. The position we need to return is where the right pointer points. We don’t need to consider about the condition nums[mid]==target.

     int find(int[] nums, int target) {
         int left = 0, right = nums.length-1;
         while (left <= right) {
             int mid = left + (right - left) / 2;
             if (nums[mid] < target) left = mid + 1;
             else right = mid-1;
         }
         return right;
     }
    

Leetcode problem: Heaters, Arranging Coins, Valid Perfect Square,Max Sum of Rectangle No Larger Than K,Russian Doll Envelopes, Valid Triangle Number

  1. Find the first value which is larger than the target value/ the last value which is not larger than the target value. This one is similar to the last one.

     int find(int[] nums, int target) {
         int left = 0, right = nums.length-1;
         while (left <= right) {
             int mid = left + (right - left) / 2;
             if (nums[mid] <= target) left = mid + 1;
             else right = mid-1;
         }
         return right;
     }
    

Leetcode problem: Kth Smallest Element in a Sorted Matrix, Sqrt(x)

There are some other problems which can be solved by binary search as a small part of the solution. And for those difficult problems, the target value may change. The solution to solve these difficult problems depends on different requirements.

When we try to use binary search on a 2D matrix, there are two ways. One way is use binary search for row and column separately. The other way is treat a 2D matrix as 1D array. Map 2D coordinates to 1D coordinate. RUNOOB game2

Closest Element to Target

RUNOOB game2

Find the first & last target

RUNOOB game2

Closest k Elements

RUNOOB game2

K-th Smallest in two sorted arrays

RUNOOB game2 RUNOOB game2 RUNOOB game2

K-th closest elements

RUNOOB game2

Binary search with unknown size

RUNOOB game2 RUNOOB game2 RUNOOB game2

69. Sqrt(x) (Easy)

This is the second kind of binary search. Find the last value which is smaller than sqrt(target).

Time complexity is O(logx). Space complexity is O(1). Here is the link.

    public int mySqrt(int x) {
        int left = 1;
        int right = x;
        while(left<=right){
            int mid = left+ (right - left) / 2;
            int sqrt = x/mid;
            if(sqrt == mid)return mid;
            else if(mid>sqrt) right = mid-1;
            else left = mid+1;
        }
        return right;
    }

744. Find Smallest Letter Greater Than Target (Easy)

This is the third version of binary search. Find the first value which is larger than the target value. We need to return (right+1), because right means the the last value which is not larger than the target value. And the problems said ‘Letters also wrap around’, so we need to update right if right is equal the length of array.

Time complexity is O(logn). Space complexity is O(1). Here is the link.

public char nextGreatestLetter(char[] letters, char target) {
    int left = 0;
    int right = letters.length-1;
    while(left<=right){
        int mid = left+ (right-left)/2;
        if(letters[mid]-target<=0)left = mid+1;
        else right = mid - 1;
    }
    if(right+1 == letters.length)right = -1;
    return letters[right+1];
}

540. Single Element in a Sorted Array (Medium)

At first, we find a rule. nums[i] = nums[i+1] (i=0,2,4,6…), iff the subarray doesn’t contain the single element. Therefor, we ensure the value of mid is even in while loop, and check if it satisfies nums[i] = nums[i+1]. If the result is true, this means the left part doesn’t have the single element, we need to continue to check the right part. Otherwise, we check the left part.

Time complexity is O(logn). Space complexity is O(1). Here is the link.

    public int singleNonDuplicate(int[] nums) {
        int left = 0;
        int right = nums.length-1;
        while(left<right){
            int mid = left + (right -left)/2;
            if(mid%2==1)mid--;
            if(nums[mid]==nums[mid+1])left = mid +2;
            else right = mid;
        }
        return nums[left];
    }

278. First Bad Version (Easy)

Time complexity is O(logn). Space complexity is O(1). Here is the link.

    public int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        while(left<right){
            int mid = left + (right - left)/2;
            if(isBadVersion(mid))right = mid;
            else left = mid + 1;
        }
        return right;
    }

153. Find Minimum in Rotated Sorted Array (Medium)

For this problem, we need to find the minimum value. The array is rotated sorted. This means we need to decide search which part(left or right) of the array at first. If nums[mid]>nums[right], this means the left part is sorted and the minimum value is at the right part. Otherwise, we check left art.

Time complexity is O(logn). Space complexity is O(1). Here is the link.

    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length-1;
        while(left<right){
            int mid = left + (right - left)/2;
            if(nums[mid]>nums[right]){
                left = mid + 1;
            }
            else{
                right = mid;
            }
        }
        return nums[right];
    }

34. Find First and Last Position of Element in Sorted Array (Medium)

This problem combine the second and third version of binary search. We need to find the first value which is not smaller than the target value as the first position. We also need to find the last value which is not larger than the target value as the last position. What’s more, if we cannot find the start position for the target value, this means we cannot find the last position of the target value, return {-1,-1}.

Time complexity is O(logn). Space complexity is O(1). Here is the link.

public int[] searchRange(int[] nums, int target) {
    if(nums.length == 0)return new int[]{-1,-1};
    int []ans = new int[]{-1,-1};
    int left = 0;
    int right = nums.length-1;
    while(left<=right){
        int mid = left + (right-left)/2;
        if(nums[mid]<target)left = mid + 1;
        else right = mid - 1;
    }
    
    if(right+1==nums.length || nums[right+1]!=target)return ans;
    ans[0] = right+1;
    left = 0; right = nums.length-1;
    while(left<=right){
        int mid = left + (right-left)/2;
        if(nums[mid]<=target)left = mid + 1;
        else right = mid - 1;
    }
    ans[1] = right;
    return ans;
}

475. Heaters (Easy)

I don’t think this problem is easy, at least medium. The problem asks us to cover all houses. Then we need to iterate houses and make sure they are covered. At first, we need to sort two arrays. In order to cover each house, we need to find two/one adjacent heaters around each house. If one house has two adjacent heaters, we need to calculate the closer heater. The distance between the closest heater and this house is the radius that this house can be covered. If one house has one adjacent heater, this means the index of this adjacent heater must be 0 or heaters.length-1. We just need to calculate the distance between the house and the heater. The important idea of this problem is you need to calculate the distance between each house and its closest heater. This distance is the minimum radius to cover this house. And we need to update radius in each iteration to make sure all houses are covered.

In this problem, we can use binary search to reduce time complexity. Binary search can help us find the target value more quickly. I searched for the first heater which is not smaller than the house. And I compare the distance between this heater and the house with the distance between last heater and house. Make sure these two heaters are adjacent heaters of this house. You can also find the last heater which is not larger than the target house. And compare with next heater.

Time complexity is O(nlogn + mlogm + nlogm). n is the size of houses. m is the size of heaters. Space complexity is O(1). Here is the link.

public int findRadius(int[] houses, int[] heaters) {
    Arrays.sort(houses);
    Arrays.sort(heaters);
    int ans = 0;
    for(int i = 0;i<houses.length;i++){
        int left = 0;
        int right = heaters.length-1;
        while(left<=right){
            int mid = left + (right - left)/2;
            if(heaters[mid]<houses[i])left = mid +1;
            else right = mid - 1;
        }
        int diffLast = left==0?Integer.MAX_VALUE:Math.abs(houses[i]-heaters[left-1]);
        int diffCur = left == heaters.length?Integer.MAX_VALUE:Math.abs(houses[i]-heaters[left]);
        ans = Math.max(ans,Math.min(diffLast,diffCur));
        
    }
    return ans;
}

611. Valid Triangle Number (Medium)

A valid triangle means the sum of the length of any two edges must be larger than the third one. We can use binary search to solve this problem. At first, we find two edges and take them as two shorter edges. We calculate the sum of the length of two edges. And this sum is the target value of binary search. We need to find the last value which is smaller than the target value. And we use the index of this value to minus another index of edge. Then we will know how many valid triangles can be built by two shorter edges.

Time complexity is O(n^2logn). Space complexity is O(1). Here is the link.

public int triangleNumber(int[] nums) {
    Arrays.sort(nums);
    int ans = 0;
    for(int i =0;i<nums.length;i++){
        for(int j =i+1;j<nums.length;j++){
            int left = j+1;
            int right = nums.length-1;
            int target = nums[i]+nums[j];
            while(left<=right){
                int mid = left + (right-left)/2;
                if(nums[mid] < target)left = mid +1;
                else right = mid - 1;
            }
            ans += right - j;
        }
    }
    return ans;
}

378. Kth Smallest Element in a Sorted Matrix (Medium)

First of all, we can also use heapsort to solve this problem. But time complexity and space complexity are too high. Now, we consider to use binary search to deal with this problem.

We need to find kth smallest element which means we need to know how many elements are smaller than a target value. In function ‘kthSmallest’, we start a binary search. The initial target value is middle number of the smallest and largest value of the matrix. We need to know how many elements are smaller than the target value in the matrix.

Function ‘binary’ shows how to find the number of elements which are smaller than the target value in a matrix. The matrix is sorted. We start from left bottom corner. If it’s smaller than the target value, this means the elements on this column are smaller than the target value. We plus (i+1) to the number of elements which are smaller than the target value. Otherwise, we move up.

Time complexity is O(nlogx). x is matrix[matrix.length-1][matrix[0].length-1] - matrix[0][0]. Space complexity is O(1). Here is thelink.

public int kthSmallest(int[][] matrix, int k) {
    int left = matrix[0][0];
    int right = matrix[matrix.length-1][matrix[0].length-1];
    while(left<=right){
        int mid = left + (right-left)/2;
        int cnt = 0;
        cnt+=binary(matrix,mid);
        
        if(cnt >= k)right = mid - 1;
        else left = mid+1;
    }
    return left;
}

public int binary(int[][]matrix,int target){
    int i = matrix.length-1;
    int j = 0;
    int ans = 0;
    while(j<matrix[0].length && i>=0){
        if(matrix[i][j]<=target){
            j++;
            ans+=i+1;
        }
        else{
            i--;
        }
    }
    return ans;
}