两个排序列表交叉的最快算法是什么?

时间:2016-11-10 12:24:55

标签: algorithm

假设有两个排序列表:A和B.

A和B中的条目数可能会有所不同。 (它们可能非常小/很大。它们可能彼此相似/显着不同)。

已知什么是此功能的最快算法?

任何人都可以给我一个想法或参考吗?

3 个答案:

答案 0 :(得分:5)

假设Am个元素,Bn个元素,m ≥ n。从理论上讲,我们能做的最好的事情就是

   (m + n)!
lg -------- = n lg (m/n) + O(n)
    m!  n!

比较,因为为了验证空交集,我们基本上必须执行排序合并。我们可以通过迭代B并在A中保留一个“光标”来指示应该插入B的最新元素以保持的位置,从而获得此限制的常数因子。排序顺序。我们使用exponential search来推进光标,总成本大约为

lg x_1 + lg x_2 + ... + lg x_n,

其中x_1 + x_2 + ... + x_n = m + nm的某个整数分区。 O(n lg (m/n))的凹度为lg

答案 1 :(得分:2)

我不知道这是否是最快的选项,但这是O(n+m)中运行的选项,其中nm是您的列表的大小:

  • 循环遍历两个列表,直到其中一个列表为空,如下所示:
  • 一对一推进。
  • 在另一个列表中前进,直到找到一个等于或大于另一个列表当前值的值。
  • 如果它相等,则元素属于交集,您可以将其附加到另一个列表
  • 如果它大于另一个元素,则在另一个列表中前进,直到找到等于或大于此值的值
  • 如上所述,重复这个,直到其中一个列表为空

答案 2 :(得分:0)

这是一个简单且经过测试的Python实现,它使用对分搜索来推进两个列表的指针。
假定两个输入列表都已排序并且不包含重复项。

import bisect

def compute_intersection_list(l1, l2):
    # A is the smaller list
    A, B = (l1, l2) if len(l1) < len(l2) else (l2, l1)
    i = 0
    j = 0
    intersection_list = []
    while i < len(A) and j < len(B):
        if A[i] == B[j]:
            intersection_list.append(A[i])
            i += 1
            j += 1
        elif A[i] < B[j]:
            i = bisect.bisect_left(A, B[j], lo=i+1)
        else:
            j = bisect.bisect_left(B, A[i], lo=j+1)
    return intersection_list


# test on many random cases
import random

MM = 100  # max value

for _ in range(10000):
    M1 = random.randint(0, MM)  # random max value
    N1 = random.randint(0, M1)  # random number of values
    M2 = random.randint(0, MM)  # random max value
    N2 = random.randint(0, M2)  # random number of values
    a = sorted(random.sample(range(M1), N1))  # sampling without replacement to have no duplicates
    b = sorted(random.sample(range(M2), N2))
    assert compute_intersection_list(a, b) == sorted(set(a).intersection(b))