003 · Binary Search

algorithm
Published

April 17, 2026

My First Thoughts

题目输入是一个升序数组 nums 和一个目标值 target,输出是 target 的 index;如果找不到,就返回 -1

最直接的做法是从头到尾遍历。遇到等于 target 的元素,就返回当前 index;如果走完整个数组都没找到,就返回 -1

def search(nums: list[int], target: int) -> int:
    for i, num in enumerate(nums):
        if num == target:
            return i
    return -1

这个写法是正确的,但它没有真正利用“数组已经升序”这个条件。

既然数组是升序的,如果遍历到某个数已经大于 target,后面的数只会更大,就可以提前停止:

def search(nums: list[int], target: int) -> int:
    for i, num in enumerate(nums):
        if num == target:
            return i
        if num > target:
            return -1
    return -1

这比普通遍历更聪明一些,但最坏情况下仍然要看完整个数组。例如 target 在最后一个位置,或者比所有元素都大,时间复杂度还是 \(O(n)\)


Why That Is Not Enough

题目明确要求 \(O(\log n)\),所以线性扫描不够。

升序数组真正有价值的地方是:每次看中间元素时,都可以直接排除一半范围。

  • 如果 nums[mid] == target,直接返回 mid
  • 如果 nums[mid] > target,说明答案只可能在左半边
  • 如果 nums[mid] < target,说明答案只可能在右半边

一开始容易想到把数组切成左半边或右半边继续找:

nums = nums[:mid]
nums = nums[mid + 1:]

但这样会带来两个问题。

第一,切片会创建新数组,产生额外开销。第二,更重要的是,切片之后 index 会从 0 重新开始,而题目要返回的是原数组里的 index。

所以不应该真的裁剪数组。我们只需要维护当前还可能包含答案的左右边界。


Final Idea

用两个指针 leftright 表示当前搜索范围。

每一轮取中点:

mid = (left + right) // 2

// 是整除,结果自动向下取整。数组长度是偶数时,中点会落在左半边的最后一个位置,不需要任何特殊处理。

然后比较 nums[mid]target

  1. 相等,返回 mid
  2. 中间值太大,把右边界移到 mid - 1
  3. 中间值太小,把左边界移到 mid + 1

left > right 时,说明搜索范围已经为空,返回 -1


Why It Works

因为 nums 是升序数组,所以中间元素可以把当前范围分成两部分。

如果 target 小于 nums[mid],它不可能出现在 mid 右侧;如果 target 大于 nums[mid],它不可能出现在 mid 左侧。

每次比较之后,搜索范围都会缩小一半,但 leftrightmid 始终是原数组的 index,因此不需要额外保存偏移量。


Code

def search(nums: list[int], target: int) -> int:
    left = 0
    right = len(nums) - 1

    while left <= right:
        mid = (left + right) // 2

        if nums[mid] == target:
            return mid
        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1

    return -1

Complexity

Time \(O(\log n)\) — 每次排除一半搜索范围
Space \(O(1)\) — 只维护左右边界和中点

Takeaway

在升序数组中查找目标值时,不要真的切分数组。维护 leftright 两个边界,就能在保留原始 index 的同时,每次排除一半搜索范围。二分查找的关键不是“取中位数”,而是“用中点比较结果缩小答案可能存在的区间”。


Quiz