算法小白的第一天,让我们来解决经典算法————二分法
1. 什么是二分法
二分法(又称折半查找、Binary Search)是一种高效的查找算法,适用于有序数组或列表中查找特定元素的问题。它的核心思想是通过不断将搜索区间一分为二来缩小目标值的可能位置范围,从而快速定位目标。形象来说,就如同在一本按字母顺序排列的字典中查找单词,无需逐页翻阅,而是先翻到中间位置判断大致范围,再逐步缩小查找区域,大幅减少查找步骤。
2. 二分法的适用条件
-
数据必须是有序的(升序或降序):只有数据有序,才能通过中间元素与目标值的比较,确定目标值可能存在的子区间。例如,若数组无序,比较中间元素后无法判断目标值在左半部分还是右半部分。
-
支持随机访问(例如数组,而不是链表):随机访问意味着可以通过索引直接定位到中间元素,时间复杂度为 O (1);而链表需要从头遍历到中间位置,时间复杂度为 O (n),会降低二分法的效率。
3. 经典题型LeetCode.704
在数组中查找一个数,没有则返回-1
let left = 0, right = nums.length - 1;
while (left <= right) {
const mid = Math.floor((right - left) / 2) + left;
const num = nums[mid];
if (num === target) {
return mid;
} else if (num > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
4. 二分法的细节
1. 看好二分法的区间
例如
[0,nums.length - 1] 区间内(左闭右闭)
left < right还是left <= right
答案是 left <= right
解释:当 left == right 时,[left, right] 这个区间是合法的,仍有一个元素需要判断,若使用left < right,可能会漏掉这个元素。
right = mid - 1还是right = mid
答案是right = mid - 1
解释:因为区间是左闭右闭,当中间值mid大于目标值时,目标值一定在mid左侧,且mid已被排除,所以右边界更新为mid - 1。
[0,nums.length) 区间内(左闭右开)
left < right还是left <= right
答案是 left < right
解释:右边界是开区间,即不包含right对应的元素,当left == right时,区间 [left, right) 为空,无需再判断。
right = mid - 1还是right = mid
答案是right = mid
解释:由于右边界是开区间,当中间值mid大于目标值时,目标值在mid左侧,右边界更新为mid,因为mid本身不在当前区间内。
2. 时间复杂度
| 时间复杂度 | 含义 |
|---|---|
| O(log n) | 每次都将搜索空间减少一半,效率非常高 |
3. 二分法的优缺点
| 优点 | 缺点 |
|---|---|
| 效率高,适合大数据量 | 必须有序 |
| 实现简单,逻辑清晰 | 不适用于动态变化的数据结构(如频繁插入删除) |
5. 总结
二分法是一种基于分治思想的高效查找算法,其核心在于通过不断缩小搜索区间来快速定位目标。掌握不同区间定义下的边界处理规则是学好二分法的关键,左闭右闭和左闭右开两种区间模式各有特点,需根据实际情况选择。虽然二分法对数据有有序和支持随机访问的要求,但在合适的场景下,能大幅提升查找效率,是算法学习中不可或缺的基础内容。对于算法小白来说,多动手实现不同区间模式的代码,深入理解边界条件的处理逻辑,能更好地掌握这一经典算法。