文章目录
二分查找
也称 折半查找(Binary Search)
使用前提:线性表采用顺序存储结构,表中元素按关键字有序排列
二分查找是一种基于比较目标值和数组中间元素的教科书式算法。
- 如果目标值等于中间元素,则找到目标值。
- 如果目标值较小,继续在左侧搜索。
- 如果目标值较大,则继续在右侧搜索。
寻找一个数(基本的⼆分搜索)
实现:维护两个指针left,right,指针之间是搜索区间
时间复杂度:O(logN)
空间复杂度:O(1)
public int search(int[] nums, int target) {
if(nums == null) return -1;
int left = 0, right = nums.length - 1;// 注意
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] == target) {
return mid;
}else if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}
}
return -1;
}
分析搜索区间
- while 循环的条件中是 <=
因为初始化right的赋值是nums.length - 1,不是nums.length。
前者相当于 两端都闭区间 [left, right],后者相当于左闭右开区间 [left, right),因为索引大小为 nums.length 是越界的。
我们这个算法中使用的是前者 [left, right] 两端都闭的区间。这个区间其实就是每次进行搜索的区间。
什么时候应该停止搜索呢?找到了目标值的时候可以终止:
if(nums[mid] == target)
return mid;
但如果没找到,就需要 while 循环终止,然后返回 -1。
那 while 循环什么时候应该终止?
搜索区间为空的时候应该终止,意味着你没得找了,就等于没找到嘛。
while(left <= right) 的终止条件是 left == right + 1,写成区间的形式就是 [right + 1, right],或者带个具体的数字进去 [3, 2],可见这时候区间为空,因为没有数字既大于等于 3 又小于等于 2 的吧。所以这时候 while 循环终止是正确的,直接返回 -1 即可。
while(left < right) 的终止条件是 left == right,写成区间的形式就是 [left, right],或者带个具体的数字进去 [2, 2],这时候区间非空,还有一个数 2,但此时 while 循环终止了。也就是说这区间 [2, 2] 被漏掉了,索引 2 没有被搜索,如果这时候直接返回 -1 就是错误的。
如果你非要用 while(left < right) 也可以,我们已经知道了出错的原因,就打个补丁,处理nums[left] == target的情况:
//...
while(left < right) {
// ...
}
return nums[left] == target ? left : -1;
- left = mid + 1,right = mid - 1
本算法的搜索区间是两端都闭的,