JavaScript 二分查找实战:三种场景模板与边界处理
二分查找是有序数组中高效定位元素的经典算法,也是面试高频考点。本文针对 JavaScript 环境,深入剖析寻找目标值、左侧边界及右侧边界三种常见场景,提供基于左右闭区间的标准化代码模板,重点讲解如何避免整数溢出、处理边界条件及防止死循环。
核心逻辑与通用公式
二分查找的核心在于维护一个搜索区间,每次将区间缩小一半。在 JavaScript 实现中,需特别注意以下细节:
- 中间索引计算:使用
Math.floor(left + (right - left) / 2)而非(left + right) / 2,前者可有效防止left和right数值过大时发生整数溢出。 - 分支结构:建议将所有情况用
else if清晰列出,避免使用最后的else,以便明确展示每种比较结果的执行路径。 - 边界定义:搜索区间可以是左闭右闭
[left, right]或左闭右开[left, right),这直接决定了循环条件和变量更新方式。
场景一:寻找标准目标值
适用于数组元素唯一或在未指定具体位置时查找任意一个匹配项。最常见的是 LeetCode 第 704 题“二分查找”。
第1步:确定左闭右闭区间写法
初始化 right = nums.length - 1,表示区间包含最后一个元素。当 left > right 时说明查找失败。
function search(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (nums[mid] === target) {
return mid; // 找到目标,返回索引
} else if (nums[mid] > target) {
right = mid - 1; // 目标在左侧,缩小右边界
} else {
left = mid + 1; // 目标在右侧,扩大左边界
}
}
return -1; // 未找到
}
完成判断:若返回值为 -1,说明 target 不在数组中;否则返回的索引即为目标位置。
缺陷分析
若数组为 [1, 2, 2, 2, 3] 且 target = 2,上述方法可能返回索引 1、2 或 3。若需锁定最左或最右边界,此法无法保证对数级复杂度(若线性扫描则退化)。
场景二:寻找左侧边界
用于在含重复元素的有序数组中,找到第一个等于 target 的元素索引。
第1步:选择左闭右闭区间 ([left, right])
这种方式与基础查找一致,关键在于命中目标时的处理方式不同:不立即返回,而是继续收缩右边界以寻找更左侧的位置。
function leftBound(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
// 命中目标,不返回,而是收缩右边界
right = mid - 1;
}
}
// 边界检查:left 越界或 left 指向的值不是 target
if (left >= nums.length || nums[left] !== target) {
return -1;
}
return left;
}
操作解释:当 nums[mid] === target 时,记录可能的答案并执行 right = mid - 1,继续向左搜索。循环结束后,left 指向第一个可能等于 target 的位置,需进行二次验证。
场景三:寻找右侧边界
用于在含重复元素的有序数组中,找到最后一个等于 target 的元素索引。
第1步:选择左闭右闭区间 ([left, right])
与左侧边界相反,命中目标后收缩左边界,继续向右搜索。
function rightBound(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2);
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
// 命中目标,不返回,而是扩大左边界
left = mid + 1;
}
}
// 边界检查:right 越界或 right 指向的值不是 target
if (right < 0 || nums[right] !== target) {
return -1;
}
return right;
}
注意:循环结束时,right 指向最后一个等于 target 的位置。同样需要检查 right 是否有效且值匹配。
关键总结
二分查找的实现难点不在于核心逻辑,而在于边界条件的处理。牢记以下原则可减少出错:
- 一致性:确定搜索区间类型后,全程保持逻辑一致(如左闭右闭则初始
right = length - 1,循环条件left <= right)。 - 更新策略:寻找左侧边界时,命中后
right = mid - 1;寻找右侧边界时,命中后left = mid + 1。 - 防御性编程:始终在最后对返回索引进行越界检查和值验证,确保返回值的有效性。
以上就是JavaScript中二分查找的例题详解,更多关于JavaScript算法技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













