我不知道这是否可以在线性时间内完成。如果输入中有 n 个三元组,那么在 O(n·log n) 时间内完成是很简单的。这是一种方法的草图,采用非必要的实现形式:
制作一组标记 M,最初全部清除。
创建一个数组并复制输入,首先按中间元素排序,然后在中间元素相等时按第三个元素排序。(到目前为止,时间是 O(n·log n)。)
对于每个不同的中间值,使用 key = 第三个元素创建一个 BST(二叉搜索树)。(时间又是 O(n·log n)。)
制作一个以中间值为键的哈希表,数据指向适当的 BST。也就是说,给定一个中间值 y 和第三个元素 z,我们可以在 O(1) 时间内得到中间值为 y 的三元组的 BST;由此,在 O(log n) 时间内可以找到第三个元素值最接近 z 的三元组。
对于每个三元组 t = (x,y,z),如果尚未设置标记,则使用哈希表查找对应于 x 的 BST(如果有)。在那个 BST 中,找到第三个元素最接近 z 的三元组 u。如果差值小于 10,则设置 t 和 u 的标记。(时间又是 O(n·log n)。)
重复步骤 2-5,但 BST 基于第一个元素值而不是中间值,步骤 5 中的查找基于 y 而不是 x。(虽然匹配关系是对称的,所以我们可以在步骤 5 中的每个循环设置两个标记,但一些合格的三元组最终可能没有标记;即,它们在公差范围内,但比找到的最近匹配更远。可以在步骤 5 中标记所有符合条件的三元组,但这会将最坏情况的时间从 O(n·log n) 增加到 O(n²·log n)。)
对于设置的每个标记,输出相应的三元组。
总时间:O(n·log n)。无需构建 BST 而是在已排序数组的子范围内使用二进制搜索即可实现相同的时间。
编辑:在 python 中,可以构建可用于bisect的结构,如下图所示,摘自 ipython 解释器会话。(可能有更有效的方法来执行这些步骤。)字典h
中的每个数据项都是一个适合使用搜索的数组bisect
。
In [1]: from itertools import groupby
In [2]: a=[(0,1,10), (1,2,20), (2,3,25), (0,1,15), (1,4,40), (1,4,33), (3,3,17), (2,1,19)]
In [3]: b=sorted((e[1],e[2],i) for i,e in enumerate(a)); print b
[(1, 10, 0), (1, 15, 3), (1, 19, 7), (2, 20, 1), (3, 17, 6), (3, 25, 2), (4, 33, 5), (4, 40, 4)]
In [4]: h={k:list(g) for k,g in groupby(b,lambda x: x[0])}; h
Out[4]:
{1: [(1, 10, 0), (1, 15, 3), (1, 19, 7)],
2: [(2, 20, 1)],
3: [(3, 17, 6), (3, 25, 2)],
4: [(4, 33, 5), (4, 40, 4)]}