给定一个 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
提示:
这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素。有两种方法实现,时间都是复杂度:O(log n) 空间复杂度:O(1)
实现思路:
第一种写法,我们定义了一个搜索区间为左闭右闭区间 [left, right]
。这个定义非常重要,因为它决定了我们如何更新搜索的边界。
有如下两点:
left
= right
时,搜索区间仍然包含了一个元素,这个元素有可能是我们要找的目标值。因此,在 left
等于 right
的情况下继续搜索是有意义的。
// 二分查找
function binarySearch(arr, target) {
// 将数组的第一个和最后一个元素赋值给left和right
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
const arr = [1, 3, 5, 7, 9, 11, 13];
console.log(binarySearch(arr, 7));
如果说定义 target 是在一个在左闭右开的区间里,也就是 [left, right) ,那么二分法的边界处理方式则截然不同。
有如下两点:
left
等于 right
时,区间内实际上没有任何元素,因为右边界是开区间,不包含 right
。[left, right)
,我们需要将搜索范围缩小到左半部分,并且排除掉已经检查过的 nums[middle]
。/**
* 在有序数组中查找目标值,如果找到则返回目标值的索引,否则返回-1
*
* @param arr 有序数组
* @param target 需要查找的目标值
* @returns 目标值的索引,如果未找到则返回-1
*/
function binarySearch(arr, target) {
// 将数组的第一个和最后一个元素赋值给left和right
let left = 0;
let right = arr.length - 1;
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid;
} else {
right = mid;
}
}
return -1;
}
const arr = [1, 3, 5, 7, 9, 11, 13];
console.log(binarySearch(arr, 7));
二分法的核心在于通过不断地将搜索区间一分为二,来逐步缩小搜索范围,直至找到目标值或确定目标值不存在。而在这个过程中,搜索区间的定义(是左闭右闭、左闭右开,还是其他)以及相应的边界处理方式是至关重要的。
📖参考笔记:
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- efsc.cn 版权所有 赣ICP备2024042792号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务