题目
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的target,如果目标值存在返回下标,否则返回 -1。
前提条件
数组有序,且无重复元素
循环不变量规则
区间的定义有两种:
左闭右闭 ,即[left, right]
左闭右开 ,即[left, right)
左闭右闭 [left,right]
while (left <= right) 要使用 <= ;
if (nums[middle] > target) right 要赋值为 middle - 1。
左闭右开[left,right)
while (left < right) 要使用 <;
if (nums[middle] > target) right 要赋值为 middle,因为寻找的左区间仍然是左闭右开区间。
代码(java版本)
左闭右闭(用的多一点)
class Solution {
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;
}
int left = 0, right = nums.length - 1;//因为是右闭,所以是nums.length - 1
while (left <= right) {//这里可以取等号
//((right - left) >> 1)相当于右移除二,整体相当于mid=(left+right)/2,是为了防止溢出,且位运算比/运算更快
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;//左闭
else
right = mid - 1;//右闭
}
return -1;
}
}
左闭右开[0,nums.length)
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length;//因为是右开,所以是nums.length,实际上只能取到nums.length - 1
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;
}
}
总结
二分查找过程中保持不变量,在while
寻找中每一次边界的处理都要根据区间的定义来操作。