左边界的获取索引函数采用low<high,右边界的获取索引函数采用low<=high
具体思路见注释
注意:左边界获取索引要注意向右侧移动后越界
右边界获取索引要注意向左侧移动后越界
两种越界都是一直没找到target导致的
如果找到了第一个满足target的索引,则以此为据点(两种不同边界考虑的算法),找左边界往左移动,找右边界往右移动
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> range;
range.push_back(searchLeft(nums,target));
range.push_back(searchRight(nums,target));
return range;
}
int searchLeft(vector<int> & nums, int target){
if(nums.size()==0){
return -1;
}
int high = nums.size();
//左闭右开,0-nums.size()-1为有效索引,但是high取size()
int low = 0;
int mid = 0;
while(low < high){
//当nums[mid] >= target时high向左侧移动
//左侧边界设定为mid,mid已经比较过,但要保持循环的左闭右开,所以high = mid
//直到low == high 时跳出循环
//此时high == low && nums[high] == nums[low] == nums[mid] == target
//当nums[mid] < target时left向右侧移动,mid作为右半部分的左侧边界已经比较过
//所以新左侧边界依然要保持左闭右开,为low = mid + 1
//但是可能会出现越界的问题
//当mid == high - 1 时,此时比较的nums[mid]为nums的最后一个值
//如果他依然小于target,则low依然会加一,导致low==high,超出了nums的有效索引,此时虽然满足了跳出循环的条件,但是需要返回-1,代表一直到末尾依然没搜索到
mid = low + ((high - low)>>2);//右移两位要加括号,相当于除以2
if(nums[mid] == target){
high = mid;
}
else if(nums[mid] < target){
low = mid + 1;
}
else if(nums[mid] > target){
high = mid;
}
}
if(low == nums.size()){
return -1;
//搜索都最右侧,low越界依然没有找到
}
return nums[low]==target ? low : -1;
//若low未越界,则如果它的值等于target,则找到左侧边界的index,否则没找到返回-1
}
int searchRight(vector<int> & nums, int target){
if(nums.size()==0){
return -1;
}
int high = nums.size()-1;
//左闭右闭,0-nums.size()-1为有效索引
int low = 0;
int mid = 0;
while(low <= high){
mid = low +((high - low)>>2);
if(nums[mid] == target){
low = mid + 1;
}
else if(nums[mid] < target){
low = mid + 1;
}
else if(nums[mid] > target){
high = mid - 1;
}
}
//一直到最左侧high可能最后减一然后越界
if(high < 0){
return -1;
}
return nums[high]==target ? high : -1;
}
};