这是一个面试问题,我用它来做编程练习。
**输入:**两个排序的整数数组A和B,按升序排列,大小分别为N和M
**输出:**按升序排序的整数数组C,其中包含同时出现在A和B中的元素
**约束条件:**C中不允许重复
**示例:**对于输入A = {3,6,8,9}和B = {4,5,6,9,10,11},输出应为C = {6,9}
谢谢大家的回答!总结一下,解决这个问题有两种主要的方法:
我最初的解决方案是保留两个指针,每个数组一个,交替地从左到右扫描数组,同时挑选出匹配的元素,所以当我们发现一个数组的当前元素大于第二个数组时,我们不断递增第二个数组的指针,直到我们找到当前的第一个数组元素或超过它(查找一个更大的)。我把所有匹配的都保存在一个单独的数组中,当我们到达任何一个输入数组的末尾时,这个数组就会返回。
另一种方法是线性扫描其中一个数组,同时使用二分查找在第二个数组中找到匹配项,这意味着O(N*log(M))时间,如果我们扫描A,并对它的N个元素中的每一个元素在B上进行二分查找(O(log(M))时间)。
我已经实现了这两种方法,并进行了一个实验来比较这两种方法(详细信息可以在here中找到)。当M大约是N的70倍时,当N有100万个元素时,二进制搜索方法似乎会胜出。
7条答案
按热度按时间js5cn81o1#
不如这样:
从概念上讲,它与您的类似,但包含了许多简化。
我不认为你能改进时间复杂度。
**edit:**我已经试过这段代码,它通过了所有的单元测试。
k3bvogb12#
这个问题本质上简化为一个 join 操作,然后是一个 filter 操作(删除重复项,只保留内部匹配)。
由于两个输入都已经排序,所以可以通过merge join高效地实现连接,具有O(size(a)+ size(b))。
因为连接的输出是排序的,所以 filter 操作是O(n)的,而要删除重复项,您所要做的就是检查每个元素是否与它前面的元素相同。只过滤内部匹配项是微不足道的,您只需丢弃任何不匹配的元素(外部连接)。
并行性(在连接和过滤器中)有机会获得更好的性能,例如Hadoop上的Apache Pig框架提供了合并连接的parallel implementation。
在性能和复杂性(以及可维护性)之间存在着明显的权衡,所以我认为面试问题的一个好答案确实需要考虑性能需求。
(Also注意问题中的函数 intersectSortedArrays 本质上是一个修改过的合并连接,其中过滤是在连接过程中完成的。2你可以在没有性能损失的情况下进行过滤,尽管稍微增加了内存占用)。
事实上,我怀疑大多数现代商业RDBMS在它们的连接实现中提供线程并行性,所以Hadoop版本提供的是机器级并行性(分布)。从设计的Angular 来看,也许一个好的、简单的解决方案是将数据放在数据库中,在A和B上建立索引(有效地排序数据),并使用SQL内部连接。
y1aodyip3#
使用数组列表存储结果。
dkqlctbz4#
如果你使用的是'Integer'(对象)数组,并希望使用java API方法,你可以检查下面的代码。注意,下面的代码可能比上面列出的原语方法更复杂(因为它使用了一些从一个数据结构到另一个数据结构的转换逻辑)和内存消耗(因为使用了对象)。我刚刚试过(shrugs):
并且输出:
此外,请检查此链接:Algolist - Algo to merge sorted arrays
编辑:已将散列集更改为树集
EDIT 2:现在问题已编辑完毕,我将添加一个简单的解决方案来查找交集:
ajsxfq5m5#
我不知道这样解决这个问题是否是个好主意:
说
1)初始化长度为min(m,n)数组C
2)通过检查第一个和最后一个元素,只关注公共部分。这里可以使用二进制搜索。举个例子来保存一些单词:
3).比较两个数组的 range
(end-start)
。取 range 较小的数组,比如A,对于A[start] ~ A[end]
中的每个元素A[i]
,在B[start,end]
中进行二进制搜索,4)继续3)直到处理完A[start,end]中的所有元素。
这样,如果(A和B相同),最坏情况是lg(n!)?2不确定。
平均病例?
jecbmhm36#
以下是记忆力的提升:
最好存储您的结果(C)在动态结构中,如链表,找到相交元素后创建一个数组(就像处理数组r一样)。如果A和B的数组非常大,并且期望公共元素比较少,那么这种技术将特别好(当你只需要很小的内存时,为什么要搜索一大块连续的内存呢?)。
编辑:还有一件事我会改变,这可能有点吹毛求疵,那就是当最坏情况的迭代次数事先知道时,我会避免使用无绑定循环。
k2fxgqgv7#