二分搜索
class Solution {
public:
int BinarySearch_first(vector<int>& nums,int target){
int left=0,right=nums.size()-1;//要点nums.size()-1和nums.size()
while(left<=right){//要点:<= 和 <
int mid=left+(right-left)/2;//避免两数直接相加超出范围
if(nums[mid]<target){
left = mid + 1;
}else if(nums[mid]>target){
right= mid - 1;
}else{
right=mid-1;//向左收缩
}
}
//此时 left 和 right 的位置关系是 [right, left]
if(left != nums.size()){//这个地方顺序很重要,如果left越界下一个判断条件会报错
if(nums[left]==target) return left;
}
return -1;
}
int BinarySearch_last(vector<int>& nums,int target){
int left=0,right=nums.size()-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]<target){
left = mid + 1;
}else if(nums[mid]>target){
right= mid - 1;
}else{
left=mid+1;//向右收缩
}
}
if(right != -1){
if(nums[right]==target) return right;
}
return -1;
}
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.empty()) {
return vector<int>{-1, -1};
}
int leftindex = BinarySearch_first(nums,target);
int rightindex = BinarySearch_last(nums,target);
return vector<int>{leftindex,rightindex};
}
};
class Solution {
public:
int BinarySearch_first(vector<int>& nums, int target){
int left=0;
int right=nums.size()-1;
while(left<right){
int mid=left+(right-left)/2;//向下取整
if(nums[mid]==target){
right=mid;
}else if(nums[mid]>target){
right=mid;
}else{
left=mid+1;
}
}
if(nums[left] == target){
return left;
}
return -1;
}
int BinarySearch_last(vector<int>& nums, int target){
int left=0;
int right=nums.size()-1;
while(left<right){
int mid=right-(right-left)/2;//特别注意:向上取整
if(nums[mid]==target){
left=mid;
}else if(nums[mid]>target){
right=mid-1;
}else{
left=mid;
}
}
if(nums[right] == target){//每次循环结束left==right不需要区分
return right;
}
return -1;
}
vector<int> searchRange(vector<int>& nums, int target) {
if(nums.empty()){
return vector<int>{-1,-1};
}
int leftindex=BinarySearch_first(nums,target);
int rightindex=BinarySearch_last(nums,target);
return vector<int>{leftindex,rightindex};
}
};
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftindex=BinarySearch(nums,target-1);
int rightindex=BinarySearch(nums,target)-1;
if(leftindex==nums.size()||nums[leftindex]!=target){
return vector<int> {-1,-1};
}
return vector<int> {leftindex,rightindex};
}
int BinarySearch(vector<int>& nums, int target){
int left=0,right=nums.size();
while(left<right){
int mid=left+(right-left)/2;
if(nums[mid]>target){
right=mid;
}else{
left=mid+1;
}
}
return left;
}
};
—————————————————————————————
二分搜索细节整理
while (left <= right) 一般是简单问题用,在循环体里能找到答案以后退出。
在退出循环的时候 left = right + 1,即 right 在左,left 在右;
while (left < right) 复杂问题用,把答案留到退出循环以后,再判断。
在退出循环的时候,有 left == right 成立
第二种方法优势在于边界问题,需要考虑的细节最少
—————————————————————————————
二分搜索问题整理
while(left<=right)
1.寻找目标元素出现的位置
如果等于,就可以直接返回 return mid;
如果严格大于,就往右边查找 left=mid+1;
如果严格小于,就往左边查找 right=mid-1;
2.寻找目标元素出现的第一个位置
如果等于,区间就向左收缩 right=mid-1;
如果严格大于,就往右边查找 left=mid+1;
如果严格小于,就往左边查找 right=mid-1;
3.寻找目标元素出现的最后一个位置
如果等于,区间就向右收缩 left=mid+1;
如果严格大于,就往右边查找 left=mid+1;
如果严格小于,就往左边查找 right=mid-1;
//此时 left 和 right 的位置关系是 [right, left]
//注意此时left是第一次元素出现的位置
if(left != nums.size()){//这个地方顺序很重要,如果left越界下一个判断条件会报错
//需要单独判断left是否越界
if(nums[left]==target) return left;
}
return -1;
//同理
if(right != -1){
if(nums[right]==target) return right;
}
return -1;