题目
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
解题思路
- left,right 两个指针分别指向当前搜索的起点和终点索引。
- 不需要记住下面这个
let mid = start + ((end - start) >> 1);
之所以不用let mid = (start - end)/2
,只是因为>>
移位运算比除法操作性能好很多,另外就是考虑到大数溢出的情况。 - 二分搜索只要理解搜索区间就够了,以下面的代码举例,搜索区间就是前闭后闭而不是前闭后开,如果是前闭后开,那
end
的初始值是nums.length
。 - 我们想下为什么下面的代码是
while (start <= end)
,结束循环的是不是start
刚好大于end
,具体举例来说搜索区间最后结束的时候是[3,2],没有任何一个数是既大于 3 又小于 2 的。 - 为什么
end = mid - 1
和start = mid + 1
而不是不需要 +1,举例来说初始的搜索区间是[0,5], mid=2,假设这时候mid
索引对应的值不等于要找的数,那我们下次要的搜索区间就是[0,1]和[3,5],因为mid
已经对比过了,新的搜索区间要排除mid
。
代码:
/** * @param {number[]} nums * @param {number} target * @return {number} */ var search = function (nums, target) { if (nums == null || !nums.length) { return -1; } let left = 0, right = nums.length - 1; // 左闭右闭 结束的时候是[3,2]才有可能是空集 while (left <= right) { let mid = left + ((right - left) >> 1); if(nums[mid] < target){ // 右区间找,left 重新赋值。区间范围[mid+1,right] left = mid + 1 ; }else if(nums[mid] > target){ //左区间找,right,重新赋值,区间范围 [left ,mid-1] right = mid - 1; }else{ return mid } } return -1; };
力扣原题连接:点击这里