基于双变量键的二分查找:有序数对数组的最小符合元素查询
嘿,这个问题确实可以用二分查找来高效解决,核心是利用数组已有的排序特性(x升序,同x下y升序)来减少不必要的遍历。我来给你拆解具体步骤和实现思路:
核心思路
我们要找的是满足c>a且d>b的最小数对,这里的“最小”定义是:先比较x,x越小越优先;x相同则y越小越优先。基于数组的排序特性,我们可以分两步走:
- 先定位到所有x>a的数对范围;
- 在这些数对中,找到x最小的组,再在该组里找最小的y>b;如果当前x组没有满足条件的y,就继续找下一个更大的x组,直到找到为止。
具体实现步骤
1. 预处理分组(可选但推荐)
因为原数组已经按x升序、同x下y升序排列,我们可以先把数组按x分组,每个组内的y列表天然是升序的,这样后续二分查找y会更方便:
# 示例输入数组 pairs = [(2,3),(2,4),(3,2),(3,4),(3,5)] # 预处理:按x分组,存储每个x对应的y列表 x_to_ys = {} sorted_x = [] for x, y in pairs: if x not in x_to_ys: x_to_ys[x] = [] sorted_x.append(x) x_to_ys[x].append(y)
这里sorted_x是严格升序的不同x值列表,x_to_ys则存储每个x对应的y升序列表。
2. 用二分查找定位目标x范围
我们需要找到第一个大于a的x的位置,这可以用bisect模块的bisect_right方法:
import bisect a, b = 2, 3 # 找到第一个x > a的索引 x_idx = bisect.bisect_right(sorted_x, a)
bisect_right会返回插入a后不破坏sorted_x升序的位置,也就是第一个大于a的x的索引。
3. 在目标x组中找最小的y>b
从x_idx开始遍历每个x组,对每个组的y列表用二分查找找第一个大于b的y:
result = None while x_idx < len(sorted_x): current_x = sorted_x[x_idx] ys = x_to_ys[current_x] # 找到第一个y > b的索引 y_idx = bisect.bisect_right(ys, b) if y_idx < len(ys): # 找到满足条件的最小y result = (current_x, ys[y_idx]) break # 因为x是升序的,第一个满足的就是最小的数对,直接退出 x_idx += 1 # 输出结果 print(result) # 对于a=2,b=3,输出(3,4)
为什么这个方法高效?
- 定位x范围用了O(log N)的二分查找(N是不同x的数量);
- 每个x组内找y用了O(log M)的二分查找(M是该x组的y数量);
- 一旦找到第一个满足条件的x组和y,就可以直接返回,不需要遍历后续元素,最坏情况下才会遍历所有x组,但实际中通常很快就能找到。
特殊情况处理
- 如果没有任何数对满足c>a且d>b,
result会是None,你可以根据需求返回提示信息; - 如果a比所有x都大,同样返回
None; - 如果某个x组的所有y都<=b,就跳过该组,继续检查下一个更大的x组。
内容的提问来源于stack exchange,提问作者Vedant Dixit
相关产品推荐
相关产品推荐

