这是我在面试时遇到的问题。有两个排序的数组A和B.检查数组A中的每个元素是否出现在数组B中。假设有无限的CPU核心。采访者建议算法应该在O(1)中运行。我只想出了一个O(log(n))解决方案。有什么想法吗?
P.S。我的O(log(n))解决方案是将A中的一个元素分配给一个CPU核心,每个CPU使用二进制搜索来检查该元素是否存在于数组B中。我记得访谈者可能已经建议二进制搜索可以是给定无限CPU优化到O(1)。但我不确定。以防万一。
答案 0 :(得分:2)
以下是公共CRCW模型中的O(1)PRAM algorithm,即只有在写入相同值时才能进行并发写入。假设原始数组A有n个元素,B的大小为m。
found = new bool[n]
parallel for i in 0..n-1:
found[i] = false
parallel for j in 0..m-1:
if A[i] == B[j]:
found[i] = true
result = true
parallel for i in 0..n-1:
if !found[i]:
result = false
print result ? "Yes": "No"
当然,我并不完全确定这是一个多么实用的模型。实际上,您可能没有并发写入。在具有独占写入的CREW模型中,您可以在O(log log n)时间内计算AND和OR聚合,并且我认为也存在相应的下限。
向面试官询问他感兴趣的并行模型的具体情况可能是个好主意。
答案 1 :(得分:2)
让每个核心从A中获取一个元素,从B中获取一对相邻元素。为每个可能的组合使用不同的核心。核心将各自比较他们的三个元素。如果A中的元素介于两者之间(并且不等于任何一个),则A中的元素不会出现在B中。
这缺少一些明显的优化。例如,a1000不需要与b1& b2,但有无限的机器,谁在乎。
答案 2 :(得分:1)
设A总计 a 元素,B总计 b 元素(我假设元素可能重复)。
我们需要总((a * b)+ 1)核心:我们想检查B中A的每个元素。所以我们需要总 b 处理A的每个元素,因此 a * b 。最后 +1 用于运行主程序的主处理器。
每个处理器将简单地比较两个元素是否相等。如果是,则会返回true
,否则为false
。以A [0]为例。我们只是比较B的任何元素是否等于A [0]。因此我们将A [0]和B [0]传递给第一个处理器,A [0]和B [1]传递给第二个处理器,依此类推,并对结果进行OR运算。相应地,将在每个核心上运行的test()
方法的代码为:
public static bool test (int aElement, int bElement)
{
return aElement == bElement;
}
接下来我们对A [1]进行相同的处理,然后A [2]直到A [a-1]并行。
我们对此结果进行AND,例如:
(test(A[0], B[0]) || test(A[0], B[1])...) && (test(A[1], B[0]) || test(A[1], B[1])... )
因此,Main()
将如下所示:
public void Main (string[] args)
{
//Read A and B arrays and create the next line dynamically
var allPresent = (test(A[0], B[0]) || test(A[0], B[1]) ||... test(A[0], B[b-1]))
&& (test(A[1], B[0]) || test(A[1], B[1]) ||... test(A[1], B[b-1]))
.
.
.
&& (test(A[a-1], B[0]) || test(A[a-1], B[1]) ||... test(A[a-1], B[b-1]))
Console.WriteLine("All Elements {0}", (allPresent ? "Found" : "Not Found"));
}
我们并行生成所有test(A[k], B[l])
,结果为O(1)时间。
答案 3 :(得分:0)
为了补充Niklas B.的非常好的答案,我补充说,对于O(1)解决方案,我怀疑在最坏的情况下,即使使用有序数组,也可以使用低于Ω(MN)的内核。< / p>
如果所有元素在两个数组中都出现一次(并且隐式地M = N),则可以在“面对”元素之间并行执行N次比较,即使用Θ(N)核。
但是当允许重复时,相等的元素可以出现移位,移位可以增大到Ω(M + N)并且事先不知道。要尝试所有元素的所有可能移位,请执行Ω(MN)比较。