Beginners tend to underestimate the function of binary search after learning binary search. It has a wider range of usage scenarios , not just looking for specific values . Random changes will greatly change the function of binary search.
Just like Knuth The boss (the one who invented the KMP algorithm) said binary search:
The idea is simple, the devil is in the details.
This article mainly introduces from binary search 两种形式实现
to 题目训练
strengthening the understanding and use of binary search, and more importantly, to learn to be flexible
Table of contents
Two implementations of binary search
As the saying goes, nothing changes
These two writing methods are the basis of binary search, and any change is inseparable from these two writing methods.
This is the basic framework of binary search:
int Search(int[] nums,int len,int target)
{
int left = 0, right = ...;
while(...)
{
int mid = left + (right - left) / 2;
//不直接相加除2是为了防止溢出
if (nums[mid] > target)
right = ...
else if (nums[mid] < target)
left = mid + 1;
else
return mid;
}
return -1;
}
We found that the only thing that needed to change in this framework was the case of while
the main loop and this is where the binary search details and the devilnums[mid]>target
We also need to know that binary search can traverse the array at least once if we want to search, and there are two commonly used methods to traverse this array: left closed right open and left closed right closed
Close left and close right
So what is left-closed-right-closed?
Let's look at the following example:
If there is an array {1, 2, 3, 4}
, then the subscript is {0, 1, 2, 3}
, then left=0; right=len-1;
then the subscript of the search range is[left,right]
, which is what we say left closed right closed
Next, look at the two places that need to be changed:
Now that we have the subscript range of retrieval
, we can knowleft==right
that when is meaningful,
the main loop can be written aswhile(left<=right)
whiletarget < arr[mid]
, becausetarget!=arr[mid]
soright=mid-1
Code:
int search(int arr[], int len, int target)
//target是查找的目标值
{
int left = 0;
int right = len - 1;
while (left <= right)
{
int mid = (right - left) / 2 + left;
if (target < arr[mid])
right = mid - 1;
else if (target > arr[mid])
left = mid + 1;
else
return mid;
}
return -1;
}
left closed right open
What is left-closed-right-open?
If there is an array {1, 2, 3, 4}
, then the subscript is {0, 1, 2, 3},
then left=0; right=len;
then the subscript of the search range is[left,right)
, which is what we call left close right open
Next, look at two details:
Now that we have the subscript range of the search,
we can knowleft==right
that time is meaningless .
The main loop can be written aswhile(left<right)
whiletarget < arr[mid]
time, becausetarget!=arr[mid]
it is a left-closed right-open interval ,
soright=mid
there is no need to recheck arr[mid]
Code:
int search(int arr[], int len, int target)
{
int left = 0;
int right = len ;
while (left < right)
{
int mid = (right - left) / 2 + left;
if (target < arr[mid])
right = mid;
else if (target > arr[mid])
left = mid + 1;
else
return mid;
}
return -1;
}
topic training
Minimum number of rotated arrays
Niuke link , the link is here.
I believe that everyone has heard such a sentence when learning binary search. The premise of binary search is an ordered array , but is this really the case?
The answer is obviously no,
If it is clear that after the dichotomy, the answer exists on one side of the dichotomy, then dichotomy can be used.
Ideas:
We found that this question did not give the target value
. If there is a target value target, then directly compare arr[mid] with target.
If there is no target value, it can generally be considered.端点
Here we consider the right endpoint .
At that time At that time , it means that mid is on the right side of the minimum value, but it is not sure whether mid is the minimum value . The left-closed right-open interval, so in the main loop because there will be repeated phenomena, so when repeatedarr[mid]>target
arr[mid]<target
right=mid
left<rigth
right--
Code:
int minNumberInRotateArray(int* nums, int numsLen )
{
// write code here二分查找
int right=numsLen-1;
int left=0;
int mid=0;
while(left<right)
{
mid=(left+right)/2;
if(nums[mid]>nums[right])
//利用right是因为利用右界实现比左界便捷,不需要额外的判断
//情况1 :1 2 3 4 5 , nums[mid] = 3. target = 1,
//nums[mid] > target, 答案在mid 的左侧
//情况2 :3 4 5 1 2 , nums[mid] = 5, target = 3,
//nums[mid] > target, 答案却在mid 的右侧
left=mid+1;
else if(nums[mid]<nums[right])
right=mid;
else
right--;
//使用left++时会跳过最小值
//例如当直接为顺序数组时,会直接跳过
}
return nums[left];
}
The number of times a number appears in an ascending array (upper and lower bounds problem)
Niuke link , the link is here.
Ideas:
The first time I saw this question, I thought of binary search, because this question is also looking for a number, but it is the upper and lower bounds of this number, but
we need to make some adjustments,
for example, when looking for the left bound, the equality needs to be shifted to the left, and when looking for the right bound , equal to the right,
but also pay attention to the judgment of special circumstances
Code:
int GetNumberOfK(int* data, int dataLen, int k)
{
// write code here
if (dataLen == 0)
//特殊情况,数组长度为0
return 0;
else if (data[dataLen - 1]<k || data[0]>k)
//特殊情况,k小于或大于最小值或最大值
return 0;
else
{
int leftbound, rightbound;
int mid;
int left = 0, right = dataLen - 1;
if (left == right)
return k == data[left];
else
{
//寻找左界
while (left <= right)
{
//可以利用第一种情况,左闭右闭
//第二种也可以,但是要改主循环条件为left<right
//right要=mid
mid = (left + right) / 2;
if (data[mid] > k)
right = mid - 1;
else if (data[mid] < k)
left = mid + 1;
else
right--;
}
leftbound = left;
//寻找右界
left = 0, right = dataLen - 1;
while (left <= right)
{
mid = (left + right) / 2;
if (data[mid] > k)
right = mid - 1;
else if (data[mid] < k)
left = mid + 1;
else
left++;
rightbound = right;
}
return rightbound - leftbound + 1;
}
}
}
If there is a mistake, welcome to correct it, definitely correct it