Boundary value of binary search
Binary search is very simple, but it also has its difficulties. The difficulty lies in the selection of judgment conditions and boundary values, which can easily lead to boundary crossing or dead cycle.
For the judgment condition of the loop, if the search interval is a closed interval [left, right], the judgment condition should be set to while (left < = right), which is to terminate the loop in the case of left > right; If while (left < right) is used as the judgment condition in this closed interval search interval, the judgment condition is to terminate the loop when left > = right occurs. In this case, left == right is the element at the corresponding array position, resulting in incorrect search results. If the search interval is a closed interval [left, right], the judgment condition can be set to while (left < right).
For boundary values, such as ordered array = [1,2,4,4,4,4,5,6], target = 4, there are multiple target values. At this time, we want to get the index of the upper boundary target value, which is 5; Or you want to get the index of the target value of the lower boundary, which is 2. At this time, you can't find the target value and return. Instead, you need to continue to tighten the boundary and further find the boundary value. The basic implementation of left and right boundary values by binary search is as follows:
int lowerBound(vector<int> arr, int target){ int left = 0; int right = arr.size(); int pos = -1; while(left < right){ int mid = left + (right-left)/2; if(target == arr[mid]){ pos = mid; right = mid; } else if(target < arr[mid]){ right = mid; } else if(target > arr[mid]){ left = mid + 1; } } return pos; } int upperBound(vector<int> arr, int target){ int left = 0; int right = arr.size(); int pos = -1; while (left < right) { int mid = left + (right-left)/2; if(target == arr[mid]){ pos = mid; left = mid + 1; } else if(target < arr[mid]){ right = mid; } else if(target > arr[mid]){ left = mid + 1; } } return pos; }
34 find the first and last positions of elements in a sorted array
Given an incrementally ordered array of integers and a value, find the position of the first and last occurrence of the value
The input is an array and a value, and the output is the position of the first occurrence and the last occurrence of the value (starting from 0); if the value does not exist, both return values are set to - 1
Input: num = [5,7,7,8,8,10], target = 8
Output: [3,4]
Resolution:
This problem hopes to find the index of the target value of the upper boundary or the lower boundary when there are multiple target values. At this time, when using binary search to search the target value, you can't return if you find the target value, but you need to continue to tighten the boundary to further find the boundary value.
For finding the first and last positions of the target value, we use different shrinkage strategies:
- The first position is the lower boundary: after finding the target value, we update the binary search interval to the left of the midpoint and continue to find the target value
- The last position is the upper boundary: after finding the target value, we update the binary search interval to the right interval of the midpoint and continue to find the target value
class Solution { public: int lower_bound(vector<int>& nums, int target){ int left = 0, right = nums.size(); int pos = -1; while(left<right){ int mid = left + (right-left)/2; if(nums[mid]==target){ pos = mid; right = mid; }else if(nums[mid]>target){ right = mid; }else{ left = mid + 1; } } return pos; } int upper_bound(vector<int>& nums, int target){ int left = 0, right = nums.size(); int pos = -1; while(left<right){ int mid = left + (right-left)/2; if(nums[mid]==target){ pos = mid; left = mid + 1; }else if(nums[mid]>target){ right = mid; }else{ left = mid + 1; } } return pos; } vector<int> searchRange(vector<int>& nums, int target) { vector<int> ans(2,-1); if(nums.empty()){ return ans; } ans[0] = lower_bound(nums,target); ans[1] = upper_bound(nums,target); return ans; } };
So in essence, boundary contraction is to implement lower in C++ STL_ bound(),upper_ Bound() two functions
lower_bound(Iterator first, Iterator last,const T& val); upper_bound(Iterator first, Iterator last,const T& val);
Both first and last are forward iterators, [first, last] is used to specify the scope of the function; val is used to execute the target value. The return value of the function is a forward iterator. When the search is successful, the iterator points to the first element found that is less than or greater than the target value; on the contrary, if the search fails, the iterator points to the same as the last iterator.
Directly calling the corresponding method of < algorithm > in STL can be completed more concisely
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { vector<int> ans(2,-1); if(nums.empty()){ return ans; } ans[0] = std::lower_bound(nums.begin(),nums.end(),target)-nums.begin(); ans[1] = std::upper_bound(nums.begin(),nums.end(),target)-nums.begin()-1; return ans[0]>ans[1]?vector<int>{-1,-1}:ans; } };
reference material
LeetCode 101: easily brush questions with you (C + +) Chapter 4 Juhe chop! Binary search
One article takes you to brush two points to find (Video + drawing)