Skip to content

搜索算法

二分搜索是最经典的 O(log n) 算法,面试必考。

🔍二分搜索

L (left)
R (right)
M (mid)
找到
已排除
// 二分搜索 - 迭代版
function binarySearch(arr, target) {
let left = 0, right = arr.length - 1;
while (left <= right) {
// 防止整数溢出
const mid = left + Math.floor((right - left) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
📊 复杂度分析
时间: O(log n) - 每次排除一半
空间: O(1) 迭代 / O(log n) 递归
为什么是 log n?
n 个元素,每次减半:
n → n/2 → n/4 → ... → 1
需要 log₂(n) 次才能减到 1

  • 数组必须有序
  • 如果无序,先排序 O(n log n),或使用线性搜索 O(n)
// 1. 循环条件: <= 不是 <
while (left <= right) {
// 2. 防止整数溢出
const mid = left + Math.floor((right - left) / 2);
// 不要写成 (left + right) / 2,可能溢出
if (arr[mid] === target) return mid;
// 3. 缩小范围: +1 和 -1,不是 mid
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}

每次比较后,搜索范围减半:

n → n/2 → n/4 → n/8 → ... → 1

需要 log₂(n) 次才能将 n 减到 1。

nlog₂(n)最多比较次数
103.34
1006.67
1,0001010
1,000,0002020

100 万个元素只需 20 次比较!


function findFirst(arr, target) {
let left = 0, right = arr.length - 1, result = -1;
while (left <= right) {
const mid = left + Math.floor((right - left) / 2);
if (arr[mid] >= target) {
if (arr[mid] === target) result = mid;
right = mid - 1; // 继续向左找
} else {
left = mid + 1;
}
}
return result;
}

2. 查找最后一个等于 target 的位置

Section titled “2. 查找最后一个等于 target 的位置”
function findLast(arr, target) {
let left = 0, right = arr.length - 1, result = -1;
while (left <= right) {
const mid = left + Math.floor((right - left) / 2);
if (arr[mid] <= target) {
if (arr[mid] === target) result = mid;
left = mid + 1; // 继续向右找
} else {
right = mid - 1;
}
}
return result;
}
function searchRotated(arr, target) {
let left = 0, right = arr.length - 1;
while (left <= right) {
const mid = left + Math.floor((right - left) / 2);
if (arr[mid] === target) return mid;
// 判断哪半边是有序的
if (arr[left] <= arr[mid]) {
// 左半边有序
if (arr[left] <= target && target < arr[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
// 右半边有序
if (arr[mid] < target && target <= arr[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}