题目链接:704. 二分查找
题目
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
相关题目推荐:
- 35.搜索插入位置
- 34.在排序数组中查找元素的第一个和最后一个位置
- 69.x 的平方根
- 367.有效的完全平方数
二分搜索的前提:数组为有序数组,且数组中无重复元素
Java代码
方法一:左闭右闭
class Solution(){
public int search(int[] nums, target){
int left = 0, right = nums.length - 1;
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length-1])
return -1;
while (left <= right){
int mid = left + ((right-left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] > target)
right = mid - 1;
else if (nums[mid] < target)
left = mid + 1;
}
return -1;
}
}
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
方法二:左闭右开
class Solution(){
public int search(int[] nums, target){
int left = 0, right = nums.length;
if (target < nums[0] || target > nums[nums.length-1])
return -1;
while (left < right){
int mid = left + ((right-left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] > target)
right = mid;
else if (nums[mid] < target)
left = mid + 1;
}
return -1;
}
}
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
二分查找易错点
1. 左右边界更新
left和right更新根据两种方法左闭右闭[left, right]和左闭右开[left, right)
i)左闭右闭[left, right]
int left = 0, right = nums.length - 1;
...
while (left <= right){
...
right = mid - 1;
...
left = mid + 1;
}
i)左闭右开[left, right)
int left = 0, right = nums.length;
...
while (left < right){
...
right = mid;
...
left = mid + 1;
}
2. 中间值定义
int mid = left + ((right-left) >> 1)
比较>>1
位运算和/2
除二取整
n为非负数时,>>1
和/2
结果一样
n为负偶数时,>>1
和/2
结果一样
n为负奇数时,>>1
和/2
结果不一样
所以,奇数直接除2会发生截断现象,在n为负奇数时,>>1
和/2
截断方向相反
避免溢出
若定义int mid = (left + right) / 2,期中left + right很可能导致溢出