二分查找(Binary Search)是算法面试和刷题中最常见、最基础的算法之一。它的核心思想是“分而治之”,每次都把查找范围缩小一半,大大提高了查找效率。本文将用最通俗的语言,带你分析二分查找的两种常见写法
一、二分查找适用场景
二分查找适用于有序且无重复元素的数组。比如:[1, 3, 5, 7, 9] 这样的数组。
二、两种区间写法
二分查找的核心是“区间”,常见有两种写法:
- 左闭右闭区间
[left, right] - 左闭右开区间
[left, right)
这两种写法的区别主要体现在 while 循环的条件和边界的更新方式上。
1. 左闭右闭区间 [left, right]
思路
- 查找区间包含
left和right,即left <= right。 - 每次循环都判断中间值
mid是否等于目标值。 - 如果目标值比中间值小,右边界收缩为
mid - 1。 - 如果目标值比中间值大,左边界收缩为
mid + 1。
代码实现
function binarySearch(nums, target) {
let left = 0, right = nums.length - 1;
while (left <= right) { // 注意等号
let mid = left + ((right - left) >> 1); // 防止溢出
if (nums[mid] > target) {
right = mid - 1; // 去左区间
} else if (nums[mid] < target) {
left = mid + 1; // 去右区间
} else {
return mid; // 找到目标
}
}
return -1; // 没找到
}
通俗解释
想象你在一本有序的字典里查单词,每次都翻到中间那一页。如果目标单词比中间的单词靠前,就只看前半本;如果靠后,就只看后半本。每次都把查找范围缩小一半,直到找到为止。
2. 左闭右开区间 [left, right)
思路
- 查找区间包含
left,但不包含right,即left < right。 - 右边界初始化为
nums.length,而不是nums.length - 1。 - 如果目标值比中间值小,右边界收缩为
mid。 - 如果目标值比中间值大,左边界收缩为
mid + 1。
代码实现
function binarySearch(nums, target) {
let left = 0, right = nums.length;
while (left < right) { // 注意没有等号
let mid = left + ((right - left) >> 1);
if (nums[mid] > target) {
right = mid; // 去左区间
} else if (nums[mid] < target) {
left = mid + 1; // 去右区间
} else {
return mid; // 找到目标
}
}
return -1; // 没找到
}
通俗解释
还是查字典的例子,只不过这次你每次查找的区间是“左边包含,右边不包含”。这样写的好处是有些题目更容易处理边界问题。
三、两种写法的区别和选择
- 左闭右闭:区间两端都包含,循环条件是
left <= right,右边界更新为mid - 1。 - 左闭右开:区间只包含左端,循环条件是
left < right,右边界更新为mid。
两种写法本质一样,选哪种都可以,关键是要理解区间的含义,写代码时保持一致,不要混用。
四、总结
二分查找是算法的基础,掌握两种区间写法能让你在刷题和面试中游刃有余。记住:区间的定义决定了循环条件和边界更新方式。多写多练,理解透彻,算法基础就稳了!