二分查找是很经典的算法了,写的时候虽然写对了,后面看了文章才知道细节还是蛮多的。
像target所在的区间,有[left,right]和[left,right)两种写法,会极大的影响边界处理条件。实质就在于我们需要在定义的区间内对target进行搜索,而不能有任何遗漏。后面的处理要和前面的区间范围配合。
逻辑还是简单的,根据书做一个总结,以[left,right]为例
-
首先确定搜索终止条件。这种区间定义时,需要考虑left==right,因此使用while(left<=right)(这其实就是在确定当left=right时也是区间定义的搜索空间,保证搜索空间的合法性)。同时定义right=nums.size()-1,这就保证了搜索空间都在定义区间中
-
后续处理边界时更新左右边界时使用left = mid + 1 和right = mid + 1,这一方面是因为原来的mid已经搜索过了,不需要重复搜索。同时因为是双闭区间的写法,也能保证后续的所有空间被搜索到。
而当[left,right)时
- 终止条件为left<right,同时right=nums.size(),保证不遗漏搜索
- 处理边界时,left = mid + 1不变,right需要修改为right = mid,这也是很显然的,虽然mid已经搜索过了,但是下一步的搜索空间是不包含right的,如果我们让right = mid - 1,就相当于忽略了这一个元素.
最后给出代码
//[left,right],
//这里使用 vector
//[left,right]
class Solution {
public:
int search(vector
int left = 0, right = nums.size() - 1 ;
while (left <= right ){
int mid = (left + right) / 2;
if (nums[mid] < target){
left = mid + 1;
} else if (nums[mid] > target ){
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
};
//[left,right)
class Solution {
public:
int search(vector
vector
while (left < right ){
vector
if (nums[mid] < target){
left = mid + 1;
} else if (nums[mid] > target ){
right = mid ;
} else {
return mid;
}
}
return -1;
}
};