D
AI
学习工作台
算法2026-05-221 分钟阅读

二分查找模板与变体

有序数组上的边界二分、答案二分与常见坑

二分查找模板边界面试记笔记标记疑惑

基础模板:精确查找

升序无重复数组中找 target,经典闭区间写法:

def binary_search(nums, target):
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = left + (right - left) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1

mid = left + (right - left) // 2 防止 (left+right) 溢出(语言层面);语义是取中点。复杂度 O(log n),空间 O(1)。

边界二分:lower / upper bound

有重复元素或需要「第一个/最后一个」位置时,不要找到就 return,而是收缩边界

  • 第一个 >= target(lower_bound)
  • 第一个 > target(即最后一个 <= 的下一个)
  • 最后一个 <= target
def lower_bound(nums, target):
    left, right = 0, len(nums)  # 半开区间 [0, n)
    while left < right:
        mid = left + (right - left) // 2
        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid
    return left  # 若 left==n 说明不存在

面试常考:搜索旋转排序数组、找峰值、平方根整数部分,本质都是判定函数 monotonic + 边界二分。

答案二分(对值二分)

当题目问「最小速度」「最大容量」「第 k 小差值」且直接枚举太慢时,在答案范围 [lo, hi] 上二分,写 check(mid) 判断是否可行:

def min_days(piles, h):
    def enough(speed):
        days = 0
        for p in piles:
            days += (p + speed - 1) // speed
        return days <= h

lo, hi = 1, max(piles) while lo < hi: mid = (lo + hi) // 2 if enough(mid): hi = mid else: lo = mid + 1 return lo

套路:1)确定 lo/hi;2)证明若 mid 可行则更大也可行(或反之);3)二分最小可行或最大可行。

常见错误与检查清单

  • 死循环right = mid 时必须用 left + (right-left)//2 的上取中;left = mid + 1 配对 right = mid - 1 要一致。
  • 区间定义:全程坚持半开或全闭,不要混用。
  • 返回值:区分「不存在」与「应插入位置」;旋转数组要比较 nums[mid]nums[left] 判断哪段有序。
练题建议:34、35、33、153、875、1011。掌握两套模板(边界 + 答案二分)可覆盖大部分二分标签题。

知识卡片

问题

二分查找的前提是什么?

点击翻转查看答案

答案

在可比较的单调性上:直接有序数组,或答案空间满足「小于某值不满足、大于等于某值满足」的二分性质。

问题

left < right 与 left <= right 两种写法核心区别?

点击翻转查看答案

答案

前者通常 right 取 n 或 n-1 表示开区间右界,循环结束时 left==right 为答案;后者闭区间 [left,right],需根据 mid 更新避免死循环。

问题

「找第一个 >= x」对应哪种二分?

点击翻转查看答案

答案

左边界二分:不满足时 left=mid+1,满足时 right=mid,最终 left 为第一个满足条件的位置(lower_bound)。