给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
在看到这类题目时 只要关键字有 “有序并升序的数组” 时,用目标值查找数组是否存在并要求有返回值时 可以优先考虑二分法
下面就给大家来介绍一下 二分查找法
顾名思义 二分查找法是一种效率比较高的搜索方法 它是在有序数组中先找到中间值 公式如下
中间值 =(数组头的下标 0 + 数组尾的下标 nums.length - 1) / 2
分成左右两份 然后中间值跟目标值进行大小比较
情况1 如果中间值 < 目标值时 这就说明 目标值在右边的数组里 这时 左边间缩小 并继续查找
情况2 如果中间值 > 目标值时 目标值在左边的数组里 这时 右边间缩小 并继续查找
情况3 如果中间值 = 目标值时 这就说明 找到了 那么就返回目标值 并结束查找
至于左边间或右边间 缩小多少 就要看循环条件了
因为要循环判断 所以使用while最为合适
至于循环条件 我一般喜欢用左闭右闭
这里科普一下 什么是左闭右闭 左闭右开
左闭右闭 [0,1] 包含0到1 就比如[0,8]表示就是0到8 包含8 用符号表示 0 <= 8
左闭右开 [0,1) 包含0 不包含1 就比如 [0,8) 表示就是0到7 不包含8 用符号表示 0 < 8
只不过左闭右闭和左闭右开的缩小边间时的写法会有很小的差别
综上所述 我们就可以写出以下代码
左闭右闭的写法
while (letf <= right) {
let mid = (l + r) >>> 1
if (nums[mid] > target) r = mid - 1
else if (nums[mid] < target) l = mid + 1
else return mid
}
左闭右开的写法
while (letf < right) {
let mid = (l + r) >>> 1
if (nums[mid] > target) r = mid
else if (nums[mid] < target) l = mid + 1
else return mid
}
左闭右闭和左闭右开 定义变量的时候也有差别
左闭右闭
let l = 0, r = nums.length - 1
左闭右开
let l = 0, r = nums.length
本题的完整代码 如下
左闭右闭写法
var search = function(nums, target) {
let l = 0, r = nums.length - 1
while (l <= r) {
let min = (l + r) >>> 0
if (nums[min] > target) {
r = min - 1
} else if (nums[min] < target) {
l = min + 1
} else return min
}
return -1
};
左闭右开写法
var search = function(nums, target) {
let l = 0, r = nums.length
while (l < r) {
let mid = (l + r) >>> 1
if (nums[mid] > target) r = mid
else if (nums[mid] < target) l = mid + 1
else return mid
}
return -1
};
此文章参考代码随想录