bisect_left返回第一个≥x的位置,bisect_right返回第一个>x的位置;二者差值即重复元素个数,切片arr[left:right]可安全获取所有x,x不存在时自动为空。

遇到重复元素时,bisect_left 返回第一个可插入位置(即最左匹配索引),bisect_right 返回最后一个可插入位置的后一位(即最右匹配索引 + 1)——这是区分两者行为的核心。
为什么 bisect_left 和 bisect_right 对重复值返回不同索引?
它们不“查找元素”,而是“找插入点”:保证插入后列表仍有序。当目标值 x 多次出现时,bisect_left 找的是所有 x 的起始位置,bisect_right 找的是所有 x 结束后的下一个位置。
例如在 [1, 2, 2, 2, 3] 中查 2:
-
bisect_left(..., 2)→1(第一个2的索引) -
bisect_right(..., 2)→4(最后一个2后面的位置)
二者相减就是重复次数:bisect_right(...) - bisect_left(...)。
用 bisect_left 和 bisect_right 获取重复元素的完整范围
要拿到所有等于 x 的元素切片,直接用两个函数结果做切片即可,无需循环遍历。
示例:
import bisect arr = [1, 2, 2, 2, 3, 4, 4] x = 2 left = bisect.bisect_left(arr, x) right = bisect.bisect_right(arr, x) print(arr[left:right]) # 输出: [2, 2, 2]
注意:right 是开区间终点,所以切片写法自然成立;若 x 不存在,left == right,切片为空列表,不会报错。
常见误用:把 bisect_right 当作“最后一个匹配索引”
新手常以为 bisect_right 返回的是最后一个 x 的下标,其实它返回的是插入点——比最后一个匹配索引大 1。
容易出错的写法:
-
arr[bisect.bisect_right(arr, x)]→ 可能越界或取到下一个值 -
arr[bisect.bisect_right(arr, x) - 1]→ 当x不存在时会取到前一个无关元素
安全做法是先检查是否存在:
pos = bisect.bisect_left(arr, x) if pos <h3>性能与前提:必须确保输入已排序且无副作用</h3><p><code>bisect</code> 模块所有函数都假设输入是升序排列的 <code>list</code>。如果传入未排序、或在搜索过程中被其他线程修改,结果不可预测。</p><p>几个关键点:</p>
- 不支持
tuple或array.array(除非显式转换为list) - 对
bytes或str列表有效,但比较基于字典序 - 没有内置的降序支持;若需降序查找,要么反转逻辑(如用
-x转换),要么手动实现反向二分 - 时间复杂度是
O(log n),但切片arr[left:right]是O(k)(k 为重复个数),不是常数操作
真正容易被忽略的是:很多人在循环中反复调用 bisect_left 做“查找+删除”,却没意识到删除操作本身是 O(n),直接抵消了二分优势。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











