【发布时间】:2012-10-20 23:40:12
【问题描述】:
我们有两个排序数组 A 和 B,除了将一个与其他数组中的所有元素进行比较之外,如何设计一个最佳算法来找到具有共同元素的数组?
【问题讨论】:
标签: arrays algorithm language-agnostic
我们有两个排序数组 A 和 B,除了将一个与其他数组中的所有元素进行比较之外,如何设计一个最佳算法来找到具有共同元素的数组?
【问题讨论】:
标签: arrays algorithm language-agnostic
持有两个指针:每个数组一个。
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)(也有很好的常量)。
【讨论】:
如果两个数组的长度(例如,A 具有 N 元素,B 具有 M 元素)相似,那么最好的方法是执行 线性 搜索一个数组的元素在另一个数组中。当然,由于数组已排序,下一次搜索应该从上一次搜索停止的地方开始。这是“排序数组合并”算法中使用的经典原理。 O(N + M) 的复杂性。
如果长度明显不同(例如,M << N),那么更优化的方法是遍历较短数组的元素并使用 binary 搜索在更长的数组。在这种情况下,复杂度是O(M * log N)。
如您所见,如果M 远小于N,则O(M * log N) 优于O(N + M),否则更糟。
应该触发从一种方法切换到另一种方法的数组大小差异取决于一些实际考虑。如果应该根据您的数据进行实际实验来选择。
这两种方法(线性和二进制搜索)可以“混合”成一个算法。让我们假设M <= N。在这种情况下,让我们选择 step 值S = [N / M]。您从数组A 中取出第一个元素,并使用步骤S 对数组B 中的元素执行跨接线性搜索,这意味着您检查元素B[0], B[S], B[2*S], B[3*S], ... 等等。一旦找到可能包含您正在搜索的元素的索引范围[S*i, S*(i+1)],您将切换到在数组B 的该段内进行二进制 搜索。完毕。对A 的下一个元素的跨接线性搜索从上一个搜索停止的地方开始。 (附带说明一下,选择 S 的值等于 2 的幂可能有意义)。
这种“混合”算法是现有的两个排序数组的最渐近最优搜索/合并算法。然而,在实践中,根据数组的相对大小选择二进制或线性搜索的更简单方法效果很好。
【讨论】:
除了将一个与其他数组中的所有元素进行比较
您必须比较 A[] 和 B[] 才能知道它们是相同的——除非您非常了解它们可以保存什么样的数据。比较的性质可能有很多解决方案,可以根据需要进行优化。
如果数组是非常严格地创建的,即只有已知模式的连续值并且总是从已知点开始,您可以只查看每个数组的长度并知道所有项目是否都是公共的。
不幸的是,这听起来不像是一个非常现实或有用的数组,因此您要返回检查 B[] 中的 A[i]
【讨论】: