二分查找进阶:如何在有序数组中快速找到Upper Bound?

大家好啊!今天我们来聊一个面试中经常出现的数据结构问题------有序数组中的Upper Bound

什么是Upper Bound?

简单来说,给定一个已排序 的数组和一个目标值target,我们要找到数组中第一个大于 target的元素的索引。如果所有元素都小于等于target,则返回数组的长度(也就是数组末尾的下一个位置)。

举个例子:

  • 数组:[2, 3, 7, 10, 11, 11, 25]
  • target = 9 → 输出 3(因为arr[3] = 10 > 9
  • target = 11 → 输出 6(因为arr[6] = 25 > 11
  • target = 100 → 输出 7(所有元素都小于等于100,返回数组长度)

方法一:线性搜索(O(n))

最直观的方法就是从头到尾遍历,找到第一个大于target的元素。

python 复制代码
def upperBound(arr, target):
    n = len(arr)
    for i in range(n):
        if arr[i] > target:
            return i
    return n

虽然简单,但效率不高,时间复杂度为O(n)。

很多同学学完二分查找基础后,卡在Upper Bound这种边界变化上,光靠看代码很难真正理解指针移动的瞬间。

推荐试试一个叫图码的宝藏网站,它能用交互式动画把60多种算法 跑给你看,甚至支持输入自己的数据或上传C/C++/Java/Python代码来生成可视化,非常适合408考研数据结构期末考试 的复习场景。

现在就去体验下,边看动画边理解Upper Bound的执行过程,比死啃书本快多了。

图码-数据结构与算法交互式可视化平台

访问网站:https://totuma.cn

方法二:二分查找(O(log n))

既然数组是有序的,我们当然可以用二分查找来优化!

思路

  1. 初始化lo = 0hi = n-1res = n(默认返回数组长度)
  2. 计算mid = (lo + hi) // 2
  3. 如果arr[mid] > target,说明mid可能是候选答案,更新res = mid,然后在左半部分继续查找(因为要找第一个大于target的元素)
  4. 如果arr[mid] <= target,说明答案一定在右半部分
python 复制代码
def upperBound(arr, target):
    lo, hi = 0, len(arr) - 1
    res = len(arr)
    
    while lo <= hi:
        mid = lo + (hi - lo) // 2
        
        if arr[mid] > target:
            res = mid
            hi = mid - 1
        else:
            lo = mid + 1
    
    return res

为什么这样是对的?

  • arr[mid] > target时,mid是一个有效上界,但左边可能还有更小的索引满足条件,所以继续在左边找
  • arr[mid] <= target时,mid及其左边都不可能是答案,所以去右边找

方法三:用内置函数(一行搞定)

很多语言都提供了现成的函数:

Python :使用bisect模块

python 复制代码
import bisect

def upperBound(arr, target):
    return bisect.bisect_right(arr, target)

C++ :使用std::upper_bound

cpp 复制代码
#include <algorithm>
int index = upper_bound(arr.begin(), arr.end(), target) - arr.begin();

总结

方法 时间复杂度 空间复杂度
线性搜索 O(n) O(1)
二分查找 O(log n) O(1)
内置函数 O(log n) O(1)

面试小贴士

  • 如果面试官让你实现Upper Bound,记得用二分查找,不要写成线性搜索
  • 注意边界条件:当所有元素都小于等于target时,返回数组长度
  • 这个方法在搜索插入位置区间查找等问题中也非常有用

学会了的小伙伴快去试试吧!有任何问题欢迎评论区留言讨论~

相关推荐
Jasmine_llq1 分钟前
《P15800 [GESP202603 六级] 选数》
数据结构·long long·逆序线性 dp·从后往前推导·转移严格遵循题意·防止总和溢出·复杂度on
疯狂打码的少年15 分钟前
【数据结构】串(字符串):基本概念与存储
数据结构·笔记
众人皆醒我独醉36 分钟前
分布式训练与 Ring AllReduce:从单卡绝望到多卡协同
人工智能·面试·llm
LiLiYuan.1 小时前
【字符串常量池】
java·开发语言·面试
致Great2 小时前
科研人的 AI,不该只回答问题:我用字节TraeWork 跑了一遍真实研究任务
算法
纵有疾風起2 小时前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
wuyk5552 小时前
1.栈:后进先出的线性数据结构
c语言·数据结构·stm32·单片机
测试_AI_一辰2 小时前
AI Agent 评测最隐蔽的坑-记忆
人工智能·算法·ai·自动化·ai编程
lucas_AI2 小时前
给YOLO检测器插 LoRA,'插对地方'比'插什么'更要命
人工智能·算法
LuminousCPP3 小时前
数据结构-时间与复杂度|时间/空间复杂度 + 两道力扣练习 + 二分查找复盘
c语言·数据结构·经验分享·算法·leetcode