Python 查找两个排序数组的交集,在某些情况下需要少于O(m+;n)的比较

Python 查找两个排序数组的交集,在某些情况下需要少于O(m+;n)的比较,python,performance,algorithm,Python,Performance,Algorithm,以下是在O(m+n)中执行此操作的一种方法,其中m和n是两个数组的长度: import random def comm_seq(arr_1, arr_2): if len(arr_1) == 0 or len(arr_2) == 0: return [] m = len(arr_1) - 1 n = len(arr_2) - 1 if arr_1[m] == arr_2[n]: return comm_seq(arr_1[:-

以下是在
O(m+n)
中执行此操作的一种方法,其中
m
n
是两个数组的长度:

import random

def comm_seq(arr_1, arr_2):
    if len(arr_1) == 0 or len(arr_2) == 0:
        return []

    m = len(arr_1) - 1
    n = len(arr_2) - 1

    if arr_1[m] == arr_2[n]:
        return comm_seq(arr_1[:-1], arr_2[:-1]) + [arr_1[m]]

    elif arr_1[m] < arr_2[n]:
        return comm_seq(arr_1, arr_2[:-1])

    elif arr_1[m] > arr_2[n]:
        return comm_seq(arr_1[:-1], arr_2)


if __name__ == "__main__":
    arr_1 = [random.randrange(0,5) for _ in xrange(10)]
    arr_2 = [random.randrange(0,5) for _ in xrange(10)]
    arr_1.sort()
    arr_2.sort()
    print comm_seq(arr_1, arr_2)
随机导入
def通信顺序(arr_1,arr_2):
如果len(arr_1)==0或len(arr_2)==0:
返回[]
m=len(arr_1)-1
n=len(arr_2)-1
如果arr_1[m]==arr_2[n]:
返回命令序列(arr_1[:-1],arr_2[:-1])+[arr_1[m]]
elif arr_1[m]arr_2[n]:
返回命令顺序(arr_1[:-1],arr_2)
如果名称=“\uuuuu main\uuuuuuuu”:
arr_1=[random.randrange(0,5)表示xrange(10)]
arr_2=[random.randrange(0,5)表示xrange(10)]
arr_1.sort()
arr_2.sort()
打印命令顺序(arr_1,arr_2)
是否有一种技术在某些情况下使用小于
O(m+n)
的比较?例如:
arru1=[1,2,2,2,2,2,2,2,2,2100]
arru2=[1,3100]


(不寻找哈希表实现)

二进制搜索算法需要
O(logm)
时间才能在长度为m的数组中找到一个数字。 因此,如果我们从长度为m的数组中搜索长度为n的数组的每个数,其总体时间复杂度为
O(nlogm)
如果m远大于n
O(nlogm)
实际上小于
O(m+n)
。因此,在这种情况下,我们可以基于二进制搜索实现一种新的更好的解决方案


然而,这并不一定意味着二进制搜索比O(m+n)更好。实际上,只有当n可以使用哈希表保存大数组,然后扫描另一个小数组以计算两个数组的交集时,二进制搜索方法才更好

import random

def comm_seq(arr_1, arr_2):
    if len(arr_1) < len(arr_2): arr_1, arr_2 = arr_2, arr_1
    cnt = {}
    for item in arr_1: 
        cnt.setdefault(item, 0)
        cnt[item] += 1
    # save the large array in a hash_table
    ret = []
    for item in arr_2:
        p = cnt.get(item, 0)
        if p: 
            ret.append(item):
            cnt[item] -= 1
    # scan the small array and get the answer
    return ret

if __name__ == "__main__":
    arr_1 = [random.randrange(0,5) for _ in xrange(10)]
    arr_2 = [random.randrange(0,5) for _ in xrange(10)]
    arr_1.sort()
    arr_2.sort()
    print comm_seq(arr_1, arr_2)
随机导入
def通信顺序(arr_1,arr_2):
如果len(arr_1)

如果认为PY字典的操作复杂度为O(1),则总体复杂度为O(min(n,m))

,据我所知,有几种不同的方法来解决这个问题,<强>但没有一个优于O(m+n)< /强>。我不知道你怎么能有一个比这更快的算法(除非是奇怪的量子计算答案),因为你必须比较两个数组中的所有元素,否则你可能会错过一个重复的

暴力 使用两个嵌套的for循环。从第一个数组中获取每个元素,然后在第二个数组中进行线性搜索O(M*N)时间,O(1)空间

地图查找 使用查找结构,如哈希表或二进制搜索树。将所有第一个数组放入map结构中,然后循环遍历所有第二个数组,并查找map中的每个元素以查看它是否存在。无论数组是否排序,这都有效O(M*log(M)+N*log(M))表示二叉搜索树时间,O(M+N)表示哈希表时间,两者都是O(M)空间。

二进制搜索 类似于蛮力,但从第一个数组中获取每个元素,并在第二个数组中对其进行二进制搜索O(m*log(N))时间,O(1)空间

平行行走 类似于合并排序的合并部分。在每个数组的前面有两个指针。比较这两个元素,如果它们相等,则存储副本,否则将指针向前移动一个点到较小的值,并重复,直到到达其中一个数组的末尾O(M+N)时间,O(1)空间

无论如何,您必须检查两个数组中的每个元素,否则您将不知道是否找到了所有重复的元素。你可能会争论一个数组大得多或小得多的边缘情况,但这不适用于你考虑所有输入范围的算法。

如果你结合使用单侧搜索和普通二进制搜索,就可以进行O(N*log(M/N))比较。在最坏的情况下(当两个数组大小相同时),这等于O(N)=O(M+N)比较。这里M是最大数组的大小,N是较小数组中不同元素的数量

获取两个数组中最小的一个,并在第二个数组中搜索其每个元素。从单面二进制搜索开始:尝试位置M/N、2*M/N、4*M/N。。。直到找到大于所需的元素。然后使用普通二进制搜索查找位置0和2k*M/N之间的元素

如果找到匹配元素,则使用单面搜索和普通二进制搜索的相同组合来查找重复匹配元素的结束位置,并将适当数量的匹配元素复制到输出。您可以使用相同的二进制搜索组合来计算较小数组中重复元素的数量,并获取这些重复元素的最小值,以确定结果中应包含多少元素


要继续使用较小数组中的下一个元素,请使用较大数组中的起始位置,即上一步结束的位置。

“(不寻找哈希表实现)”-为什么不?是否有一个您没有告诉我们的约束,比如不允许创建另一个数据结构作为数组的索引?@mbeckish没有其他约束。我只是在寻找一个使用小于
O(m+n)
比较的比较模型的解决方案。该函数在我看来是
O(min(n,m))
而不是
O(n+m)
这里有一个更快的解决方案