我们有两个排序的数组A和B,除了比较一个与其他数组中的所有元素之外,如何设计一个最佳算法来查找具有它们共同元素的数组?
答案 0 :(得分:27)
保持两个指针:每个阵列一个。
i <- 0, j <- 0
repeat while i < length(arr1) and j < length(arr2):
if arr1[i] > arr2[j]: increase j
else if arr1[i] < arr2[j]: increase i
else : output arr[i], increase both pointers
这个想法是,如果对数据进行排序,如果元素在一个数组中“太大”,那么对于数组中剩余的所有其他元素,它将“太大” - 因为它已经过排序。
此解决方案需要对数据进行单次遍历。 O(n)
(也有很好的常量)。
答案 1 :(得分:9)
如果两个数组的长度(例如A
有N
个元素且B
有M
元素)相似,那么最好的方法是执行< em>线性搜索另一个数组中的一个数组元素。当然,由于数组已排序,因此下一次搜索应从上一次搜索停止的位置开始。这是“排序数组合并”算法中使用的经典原理。 O(N + M)
上的复杂性。
如果长度明显不同(例如,M << N
),那么更优化的方法是迭代较短数组的元素并使用二进制搜索来查找这些较长数组中的值。在这种情况下,复杂性为O(M * log N)
。
正如您所看到的,O(M * log N)
优于O(N + M)
,如果M
远小于N
,则会更糟糕。
应该触发从一种方法切换到另一种方法的数组大小的差异取决于一些实际考虑因素。如果应根据您的数据的实际实验选择。
这两种方法(线性和二进制搜索)可以“混合”到单个算法中。我们假设M <= N
。在这种情况下,让我们选择步骤值S = [N / M]
。您从数组A
获取第一个元素,并使用步骤B
对数组S
中的该元素执行 straddled 线性搜索,这意味着您检查元素{{1 }} 等等。找到可能包含您要搜索的元素的索引范围B[0], B[S], B[2*S], B[3*S], ...
后,切换到二进制搜索数组[S*i, S*(i+1)]
的该段内。完成。 B
的下一个元素的跨越线性搜索从前一个搜索停止的位置开始。 (作为旁注,选择A
的值等于2的幂可能是有意义的。)
这种“混合”算法是存在的两个有序数组的最渐近最优的搜索/合并算法。然而,在实践中,根据阵列的相对大小选择二进制或线性搜索的更简单的方法非常有效。
答案 2 :(得分:1)
除了将一个与其他数组中的所有元素进行比较
之外
你必须将A []与B []进行比较才能知道它们是相同的 - 除非你知道它们可以容纳什么样的数据。比较的性质可能有许多解决方案,可以根据需要进行优化。
如果数组是非常严格创建的,即只有已知模式的连续值,并且始终从已知点开始,您只需查看每个数组的长度,并知道所有项是否都是常见的。
遗憾的是,这听起来不是一个非常现实或有用的数组,所以你回到B []
中检查A [i]