Binary Search 二分法查找的三个模板

Parts of a Successful Binary Search

Binary Search is generally composed of 3 main sections:

  1. Pre-processing - Sort if collection is unsorted.

  2. Binary Search - Using a loop or recursion to divide search space in half after each comparison.

  3. Post-processing - Determine viable candidates in the remaining space.


Binary Search Template I

参考:https://leetcode.com/explore/learn/card/binary-search/125/template-i/950

int binarySearch(vector& nums, int target){
  if(nums.size() == 0)
    return -1;

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

  // End Condition: left > right
  return -1;
}

模板一是二分法搜索的最基本的形式,该模板用于搜索一个可以通过访问数组中的单个索引来确定的元素。搜索结束后不需要进行后处理。

Template #1 is the most basic and elementary form of Binary Search. It is the standard Binary Search Template that most high schools or universities use when they first teach students computer science. Template #1 is used to search for an element or condition which can be determined by accessing a single index in the array.

Search Condition can be determined without comparing to the element's neighbors (or use specific elements around it)
No post-processing required because at each step, you are checking to see if the element has been found. If you reach the end, then you know the element is not found

Distinguishing Syntax:

  • Initial Condition: left = 0, right = length-1
  • Termination: left > right
  • Searching Left: right = mid-1
  • Searching Right: left = mid+1

应用1:Sqrt(x)

Implement int sqrt(int x).

Compute and return the square root of x, where x is guaranteed to be a non-negative integer.

Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.

Input: 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since 
             the decimal part is truncated, 2 is returned.

在不使用牛顿法的情况下,我们使用二分法如下:

class Solution {
public:
    int mySqrt(int x) {
        if(x == 0)
            return 0;
        int left = 1, right = INT_MAX;
        while(left<=right){
            int mid = left + (right - left)/2;
            //"mid > x/mid" can prevent overflow
            if(mid > x/mid){
                right = mid - 1;
            }else{
                if(mid+1 > x/(mid+1))
                    return mid;
                left = mid + 1;
            }
        }
    }
};

1.If mid * mid > x, mid > x/mid is true, because x/mid is not greater than the real value of x/mid.
2.If mid * mid = x, because x/mid is equal to midmid > x/mid is false.
3.If mid * mid < x, because the integer part of x/mid is greater or equal to midmid <= x/mid is true. Hence mid > x/mid is false.
Therefore, if mid>x/mid is true, mid is really greater than x/mid. Further, mid is greater than sqrt(x).
When mid > x/mid is false, and mid+1 > x/mid+1 is true, we find the answer, because mid<=sqrt(x) && mid+1>sqrt(x).

 

应用二:Search in Rotated Sorted Array 在一个旋转后的有序数组中寻找一个数

https://blog.csdn.net/qq_25800311/article/details/82720942


Binary Search Template II

int binarySearch(vector& nums, int target){
  if(nums.size() == 0)
    return -1;

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

  // Post-processing:
  // End Condition: left == right
  if(left != nums.size() && nums[left] == target) return left;
  return -1;
}

Template #2 is an advanced form of Binary Search. It is used to search for an element or condition which requires accessing the current index and its immediate right neighbor's index in the array.

模板二是二分法搜索的高级形式,当在数组中搜索一个元素时需要访问当前索引元素及其右邻居索引的元素,可采用该模板。

关键属性:

  • An advanced way to implement Binary Search.
  • Search Condition needs to access element's immediate right neighbor
  • Use element's right neighbor to determine if condition is met and decide whether to go left or right
  • Gurantees Search Space is at least 2 in size at each step
  • Post-processing required. Loop/Recursion ends when you have 1 element left. Need to assess if the remaining element meets the condition.

区分语法:

  • Initial Condition: left = 0, right = length
  • Termination: left == right
  • Searching Left: right = mid
  • Searching Right: left = mid+1
  • Post-processing: need

应用实例:Find Minimum in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e.,  [0,1,2,4,5,6,7] might become  [4,5,6,7,0,1,2]).

Find the minimum element.

You may assume no duplicate exists in the array.

Example 1:

Input: [3,4,5,1,2] 
Output: 1

Example 2:

Input: [4,5,6,7,0,1,2]
Output: 0

思路:

Looking at subarray with index [start,end]. We can find out that if the first member is less than the last member, there's no rotation in the array. So we could directly return the first element in this subarray.

If the first element is larger than the last one, then we compute the element in the middle, and compare it with the first element. If value of the element in the middle is larger than the first element, we know the rotation is at the second half of this array. Else, it is in the first half in the array.

int findMin(vector &num) {
        int start=0,end=num.size()-1;
        
        while (start=num[start]) {
                start = mid+1;
            } else {
                end = mid;
            }
        }
        
        //这里没有进行后处理的原因是最小值一定存在
        return num[start];
    }

Binary Search Template III

int binarySearch(vector& nums, int target){
    if (nums.size() == 0)
        return -1;

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

    // Post-processing:
    // End Condition: left + 1 == right
    if(nums[left] == target) return left;
    if(nums[right] == target) return right;
    return -1;
}

Template #3 is another unique form of Binary Search. It is used to search for an element or condition which requires accessing the current index and its immediate left and right neighbor's index in the array.

关键属性:

  • An alternative way to implement Binary Search
  • Search Condition needs to access element's immediate left and right neighbors
  • Use element's neighbors to determine if condition is met and decide whether to go left or right
  • Gurantees Search Space is at least 3 in size at each step
  • Post-processing required. Loop/Recursion ends when you have 2 elements left. Need to assess if the remaining elements meet the condition.

区分语法:

  • Initial Condition: left = 0, right = length-1
  • Termination: left + 1 == right
  • Searching Left: right = mid
  • Searching Right: left = mid
  • Post-processing: need

应用实例:

https://blog.csdn.net/qq_25800311/article/details/82733711

https://leetcode.com/explore/learn/card/binary-search/135/template-iii/944/discuss/14699/Clean-iterative-solution-with-two-binary-searches-(with-explanation)


三个模板的对比分析

99% of binary search problems that you see online will fall into 1 of these 3 templates. Some problems can be implemented using multiple templates, but as you practice more, you will notice that some templates are more suited for certain problems than others.

Note: The templates and their differences have been colored coded below.

Binary Search 二分法查找的三个模板_第1张图片

These 3 templates differ by their:

  • left, mid, right index assignments
  • loop or recursive termination condition
  • necessity of post-processing

Template 1 and 3 are the most commonly used and almost all binary search problems can be easily implemented in one of them. Template 2 is a bit more advanced and used for certain types of problems.

Each of these 3 provided templates provide a specific use case:

Template #1 (left <= right):


  • Most basic and elementary form of Binary Search
  • Search Condition can be determined without comparing to the element's neighbors (or use specific elements around it)
  • No post-processing required because at each step, you are checking to see if the element has been found. If you reach the end, then you know the element is not found

 

Template #2 (left < right):


  • An advanced way to implement Binary Search.
  • Search Condition needs to access element's immediate right neighbor
  • Use element's right neighbor to determine if condition is met and decide whether to go left or right
  • Gurantees Search Space is at least 2 in size at each step
  • Post-processing required. Loop/Recursion ends when you have 1 element left. Need to assess if the remaining element meets the condition.

 

Template #3 (left + 1 < right):


  • An alternative way to implement Binary Search
  • Search Condition needs to access element's immediate left and right neighbors
  • Use element's neighbors to determine if condition is met and decide whether to go left or right
  • Gurantees Search Space is at least 3 in size at each step
  • Post-processing required. Loop/Recursion ends when you have 2 elements left. Need to assess if the remaining elements meet the condition.

Time and Space Complexity:


Runtime: O(log n) -- Logorithmic Time

Because Binary Search operates by applying a condition to the value in the middle of our search space and thus cutting the search space in half, in the worse case, we will have to make O(log n) comparisons, where n is the number of elements in our collection.

Why log n?

  • Binary search is performed by dividing the existing array in half.
  • So every time you a call the subroutine ( or complete one iteration ) the size reduced to half of the existing part.
  • First N become N/2, then it become N/4 and go on till it find the element or size become 1.
  • The maximum no of iterations is log N (base 2).

 

Space: O(1) -- Constant Space


Although, Binary Search does require keeping track of 3 indicies, the iterative solution does not typically require any other additional space and can be applied directly on the collection itself, therefore warrants O(1) or constant space.

你可能感兴趣的:(算法)