在二进制算法中,如何比较具有整数排序内容的两个数组?
答案 0 :(得分:3)
在每种情况下:取决于情况。
假设数组是有序的或散列的,则时间复杂度最多为O(n + m)。
您没有提到任何语言,所以它是伪代码。
function SortedSequenceOverlap(Enumerator1, Enumerator2)
{ while (Enumerator1 is not at the end and Enumerator2 is not at the end)
{ if (Enumerator1.current > Enumerator2.current)
Enumerator2.fetchNext()
else if (Enumerator2.current > Enumerator1.current)
Enumerator1.fetchNext()
else
return true
}
return false
}
如果排序顺序降序,则需要为此数组使用反向枚举器。
但是,这并不总是最快的方法。
如果其中一个数组的大小明显不同,则对较短数组的元素中的几个元素使用 binary search 可能会更有效。
这可以进一步改善,因为当您从小数组的中值元素开始时,您无需完全搜索任何其他元素。在中位元素之前之前的任何元素必须在未找到中位元素的位置之前的范围内,并且在中位元素之后的任何元素必须在在大型阵列的上限范围内。可以递归地应用它,直到找到所有元素。一旦受到打击,就可以中止。
此方法的缺点是,在最坏的情况下(即O(n log m))需要花费更多时间,并且需要随机访问阵列,这可能会影响缓存效率。
另一方面,将 small 数字(log m)相乘可能比添加 large 数字(m)更好。与上述算法相比,通常只需要访问大型数组的几个元素。
当log m小于m / n时,收支平衡点近似,其中n是较小的数字。
您认为是吗? -不
如果随机访问较大的阵列导致更高的延迟,例如由于降低了缓存效率,因此最好执行相反的操作,即从 small 数组中查找 small 数组中 large 数组的元素。大阵列。
为什么应该更快?您必须查找更多元素。
答案:
否,没有更多的查询了。一旦您期望大型数组的一系列元素的边界崩溃,您就可以停止搜索这些元素,因为您将再也找不到任何匹配。 实际上,比较的次数是完全相同的。
区别在于,第一步将大型数组的 single 元素与小型数组的不同元素进行比较。一堆比较只需要一个慢速访问,而另一种方式则需要多次访问同一元素,而其他一些元素之间需要访问。 因此,有较少的慢速访问,而有较快的访问。
(大约30年前,当您以这种方式键入内容时,我便实现了搜索,在此情况下,访问大索引需要磁盘I / O。)
答案 1 :(得分:0)
如果您知道它们已排序,则可以有一个指向每个数组开头的指针,然后在两个数组上移动,并在每次比较后向上(或向下)移动一个指针。这将使其变为O(n)。不知道可以将任何内容一分为二,因为您不知道公用号码在哪里。
比强力O(n2)还要好。
答案 2 :(得分:0)
如果您知道第二个数组已排序,则可以使用二进制搜索在第二个数组中查找第一个数组中的元素。
答案 3 :(得分:0)
这可以通过两种方式完成。 a)二进制搜索b)线性搜索
对于二进制搜索-对于数组A中的每个元素,通过二进制搜索在B中查找元素,那么在这种情况下,复杂度为O(n log n)
对于线性搜索-它是O(m + n)-其中m,n是数组的大小。在您的情况下,m = n。
线性搜索:
代码:
private int findCommonElement(int[] A, int[] B) {
for ( int i = 0, j = 0; i < A.length && j < B.length; ) {
if ( A[i] < B[j] ) {
i++;
} else if ( A[i] > B[j] ) {
j++;
}
return A[i];
}
return -1; //Assuming all integers are positive.
}
现在,如果两个都下降,则只需颠倒比较符号,即如果A[i] < B[j]
递增j
否则递增i
如果您有一个降序(B)和一个升序(A),则i
的{{1}}从数组的开头开始,A
的{{1}}从数组的结尾开始并相应地移动它们,如下所示:
j