一、前提条件
1.数组为有序数组
2.数组中无重复元素(如果有重复元素,使用二分查找法返回的元素下标可能不唯一)
二、注意点:不同的区间定义,边界条件也不同
1.第一种区间定义——[left,right]
卡哥+我自己的理解:
区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=,(并且此时nums[left(right)]处的元素还没有被查看过)
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
代码示例
public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
if(nums.length < 1){
return -1;
}
int left = 0;
int right = nums.length - 1;
int mid;
while(left <= right){
mid = left + (right - left) / 2;// 防止溢出 等同于(left + right)/2
if(nums[mid] == target){
return mid;
}else if(nums[mid] < target){
left = mid + 1;
}else{
right = mid - 1;
}
}
return -1;
}
2.第二种区间定义——[left,right)
此时,二分法的边界处理方式则截然不同。
- while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
代码示例
public int search(int[] nums, int target) {
int left = 0, right = nums.length;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;
}
return -1;
}
三、其他注意点
- 溢出问题
- left、right、mid都是下标,不是数组元素
算法刷题笔记