二分查找是既简单又困难的部分,如果序列有序,我们可以使用二分查找,总结如下:
一、递归的二分查找
递归的方法来解决二分查找。
int bsearch(vector<int>&nums,int low,int high,int target)
{
if(low>high)
return -1;
int mid=(low+high)/2;
if(nums[mid]>target)
return bsearch(nums,low,mid-1,target);
if(nums[mid]<target)
return bsearch(nums,mid+1,high,target);
return mid;
}
二、迭代的二分查找
除了递归,还可以用迭代的方式进行二分查找,前提也是序列有序。
int bsearch(vector<int>&nums,int low,int high,int target)
{
while(low<=high)
{
int mid=(low+high)/2;
if(nums[mid]>target)
high=mid-1;
if(nums[mid]<target)
low=mid+1;
else
return mid;
}
return -1;//not found
}
三、二分查找求上下界
上述两种情况是标准的二分查找,要求序列中元素有序且无重复,假如现在题目中序列存在重复元素,要求重复元素的上下界。例如 [1,2,2,3]求2的上下界(索引),为(1,2)
(1)二分查找求下界
由于计算mid的时候总是向下去整,因此,计算下界的时候需要对mid计算做一个简单的处理。
int lowerbounds(vector<int>&nums,int low,int high,int target)
{
if(low>high||nums[low]>=target)
return -1;
int mid = (low+high + 1)/2;
while(low<high)
{
if(nums[mid]<target)
low=high;
else
high=mid-1;
mid=(low+high+1)/2;
}
return mid;
}
(2)二分查找求上界
跟求下界类似。
int upperbounds(vector<int>&nums,int low,int high,int target)
{
if(low>high||nums[high]<=target)
return -1;
int mid=(low+high)/2;
while(low<high)
{
if(nums[mid]>target)
high=mid;
else
low=mid+1;
}
return mid;
}
但是考虑一些特殊情况,例如序列为[5,5,5,5],target为5,这时我们计算出来lower和upper都为-1;或者例如序列为[1,2,3,4],target为5计算出来lower为3,upper为-1,为了排除这些特殊情况,在进行二分查找之前,往nums后面添加一个INT_MAX,这样保证始终有上界。
class Solution
{
private:
int lowerbounds(vector<int>&nums,int target,int low,int high)
{
if(low>high||target<=nums[low])//不在范围
return -1;
int mid = (low+high+1)/2;
while(low<high)
{
if(nums[mid]<target)
low=mid;
else
high=mid-1;
mid = (low+high+1)/2;
}
return mid;
}
int upperbounds(vector<int>&nums,int target,int low,int high)
{
if(low>high || target>=nums[high])//不再范围
return -1;
int mid = (low + high)/2;
while(low<high)
{
if(nums[mid]>target)
high=mid;
else
low=mid+1;
mid=(low+high)/2;
}
return mid;
}
public:
vector<int> searchRange(vector<int>& nums, int target) {
nums.push_back(INT_MAX);
vector<int>res(2,-1);
int lower = lowerbounds(nums,target,0,nums.size()-1);
if(nums[lower+1]==target)
{
res[0]=lower+1;
}
else
{
return res;
}
int upper=upperbounds(nums,target,0,nums.size()-1);
res[1]=upper-1;
return res;
}
};