Leetcode Binary Search Related Problems

based on: https://github.com/yuzhoujr/leetcode/issues/8
as we mentioned before, the binary search idea can happens almost anywhere, like implement pow(x, n) function and search rotated array, and many other unexpected, not so explicit senerio.

we need to dig deeper to that binary search, and especially, the boundary problems, those are really pain in my ass for long time. Let’s get started.

Search the index where the value is exact the same as target:

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

search for the smallest number index that larger or equals to target

int binarySearch(int[] arr, int target){
     int left = 0, right = arr.length - 1;
     while (left <= right) {
         int mid = left + (right - left) / 2;
         if (arr[mid] < target) { //when mid < target
             left = mid + 1; 
         }else{ //when mid >= target
             right = mid; //
         }
      }
      return right; //that's why we return right
}

search for the largest number index that less or equals to target

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

int left = 0; int right = arr.length;
while (left < right) {
//every other stays the same
r = mid;

There are three kinds of problems in leetcode about binary search:

  1. we have a specific target
  2. we have no specific target
  3. we have no specific target and we can across boundary

for class1:
Leetcode 374. Guess Number Higher or Lower
Leetcode 367. Valid Perfect Square
33. Search in Rotated Sorted Array

for class2:
we have many transformation of such problem: like find the smallest that larger ot equals to target, or the first value that satisfy the conditions, or the last value that not satisfiy conditions.

Let’s call the template while(l<=r) as template1, and while(l<r) as template2. then what are the stop position for l and r pointer when finished?
for template1, due to while(l<=r), so when l>r, while loop will be terminated. so l will stopped at the first position larger than target, and r will stopped at the last position less than target.
for template2, due to while(l<r), and the initial position of r is len(arr), so when l>=r, the while loop will be terminated, and when r is not moving the whole time, if we return arr[l], it may out of range(that’s why when we using this template, we always return r)

Example 1: given target, find the position where target should be inserted.
we don’t know if given arr contains target value or not. so we insert them to the position that where l stops(if we want to insert it stable), or where r stops. we don;t have to do anything id arr[mid] == target

Example 2:
Last Position of Target:
given a target, find the last position where the target value appears.

class Solution:
    def lastPosition(self, nums, target):
        if not nums:
            return -1
        l , r = 0 , len(nums) - 1
        while l <= r:
            mid = l + (r-l)//2
            if nums[mid] <= target: //this is the way to elinmate duplicate in left, because when nums[mid] == target, l will move as well
                l = mid + 1
            else:
                r = mid - 1
        //so l will end at the first one that not satify
        //r will be the last one that satisfy 
        if nums[r] == target://we have to check if target is exist or not
            return r
        else:
            return -1

Seacrh for a range:
find the intervals of target exists

class Solution:
    def searchRange(self, nums, target):
        l = self.findLeft(nums, target)
        r = self.findRight(nums, target)
        return [l, r] if l <= r else [-1, -1] //we need to check if we found such a interval or not, because there may never exist such an interval


    def findLeft(self, nums, target):
        l, mid, r = 0, 0, len(nums)-1
        while l <= r:
            mid = l + (r-l)//2
            if nums[mid] < target:
                l = mid + 1
            else:
                r = mid - 1
        return l   //the first one that less or equals to target


    def findRight(self, nums, target):
        l, mid, r = 0, 0, len(nums)-1
        while l <= r:
            mid = l + (r-l)//2
            if nums[mid] <= target:
                l = mid + 1
            else:
                r = mid - 1
        return r //the last one that large or equals to target

for problem like we have no specific target, and we can also across the bound,
Find Peak Element:

class Solution:
    def findPeakElement(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        l , mid , r = 0, 0, len(nums) - 1
        while l + 1 < r:
            mid = l + (r-l)//2
            if nums[mid] < nums[mid + 1]:
                l = mid
            else:
                r = mid
        if nums[l] > nums[r]: return l
        else: return r

Find Minimum in rotateed sorted array:

class Solution(object):
    def findMin(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        l, r = 0, len(nums) - 1
        while l + 1 < r:
            mid = l + (r - l) // 2
            if nums[mid] > nums[r]:
                l = mid
            else:
                r = mid
        return min(nums[l], nums[r])

感觉上面的总结并不好

需要遵守以下原则:
永远使用l=0 r=len-1 while(L<=R) L=mid-1 R=mid+1
这会使得当退出while循环之后L=R+1
如果我们是
if(a[mid] < target) L = mid + 1;
else R = mid - 1;
那么最终位置是:a[R] <= target < a[L]
如果我们是
if(a[mid] <= target) L = mid + 1;
else R = mid - 1;
那么最终位置是:a[R] < target <= a[L]

posted @ 2020-04-29 04:21  EvanMeetTheWorld  阅读(20)  评论(0)    收藏  举报