目录
4.在排序数组中查找元素的第一个和最后一个位置(查找左区间,查找右区间)
1.算法简介
二分查找一共有三种模板
1.朴素二分查找
2.查找左区间
3.查找右区间
算法中有很多细节,建议先通过例子,理解细节,然后在区记忆模板。
2.算法原理
只要数组存在二段性,就可使用二分查找不一定是有序的数组。
3.二分查找(朴素二分查找)
判断是否有二段性
根据target可以将数组分为,两段区间,小于target和大于target的两段区间。
具有二段性,可以使用二分查找算法。
int search(vector<int>& nums, int target) {
int left = 0,right = nums.size()-1;
while(left <= right)
{
int mid = (left + right)/2;
if(target > nums[mid])
{
left = mid + 1;
}
else if(target < nums[mid])
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
注意: 为什么while(left <= right)?
因为两个指针重合时,指向元素元素还没进行判断
4.在排序数组中查找元素的第一个和最后一个位置(查找左区间,查找右区间)
判断是否有二段性
查找8的第一个位置,可以看成小于8的区间和大于等于8的区间。(查找左区间)
查找8的第一个位置,可以看成小于等于8的区间和大于8的区间。(查找右区间)
vector<int> searchRange(vector<int>& nums, int target) {
int len = nums.size();
if(len == 0)
{
return {-1,-1};
}
vector<int>ans;
int left = 0,right = len -1;
while(left < right)
{
int mid = left + (right - left)/2;
if(nums[mid] >= target)
{
right = mid;
}
else if(nums[mid] < target)
{
left = mid + 1;
}
}
if(nums[left] != target)
{
return {-1,-1};
}
ans.push_back(left);
///
left = 0,right = len - 1;
while(left < right)
{
int mid = left + (right - left+1)/2;
if(nums[mid] <= target)
{
left = mid;
}
else if(nums[mid] > target)
{
right = mid - 1;
}
}
ans.push_back(left);
return ans;
}
注意:
查找左区间
1. 为什是right = mid; 不是right = mid-1
因为如果right刚好是区间第一个8,命中条件if(nums[mid] >= target),如果是right-1就会错过结果。
2.为什么是 while(left < right) 不是while(left <= right)
当left == right 是区间第一8的位置,命中条件if(nums[mid] >= target)会陷入死循环。
查找右区间
1.为什是left = mid;不是left = mid+1;
同上
2. 为什是int mid = left + (right - left+1)/2; 不是int mid = left + (right - left)/2;
因为当元素只剩下两个的时候
int mid = left + (right - left)/2;mid会落在左边的元素上,命中条件 if(nums[mid] <= target),left会不动弹会陷入死循环
而为什是int mid = left + (right - left+1)/2mid会在右边的元素上 ,
命中条件if(nums[mid] <= target),left会到右边元素的位置循环结束。