假设我们有2个排序的整数数组,大小为n和m。找到所有m + n
个数字的中位数的最佳方法是什么?
log(n) * log(m)
复杂度很容易做到这一点。但我想在log(n) + log(m)
时间内解决这个问题。那么有什么建议可以解决这个问题吗?
答案 0 :(得分:1)
<强>解释强>
这个问题的关键是通过比较剩余A和B的中位数来逐步忽略A和B的一半:
if (aMid < bMid) Keep [aMid +1 ... n] and [bLeft ... m]
else Keep [bMid + 1 ... m] and [aLeft ... n]
// where n and m are the length of array A and B
如下所示:时间复杂度为O(log(m + n))
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length, n = B.length;
int l = (m + n + 1) / 2;
int r = (m + n + 2) / 2;
return (getkth(A, 0, B, 0, l) + getkth(A, 0, B, 0, r)) / 2.0;
}
public double getkth(int[] A, int aStart, int[] B, int bStart, int k) {
if (aStart > A.length - 1) return B[bStart + k - 1];
if (bStart > B.length - 1) return A[aStart + k - 1];
if (k == 1) return Math.min(A[aStart], B[bStart]);
int aMid = Integer.MAX_VALUE, bMid = Integer.MAX_VALUE;
if (aStart + k/2 - 1 < A.length) aMid = A[aStart + k/2 - 1];
if (bStart + k/2 - 1 < B.length) bMid = B[bStart + k/2 - 1];
if (aMid < bMid)
return getkth(A, aStart + k / 2, B, bStart, k - k / 2); // Check: aRight + bLeft
else
return getkth(A, aStart, B, bStart + k / 2, k - k / 2); // Check: bRight + aLeft
}
希望它有所帮助!如果您需要更多解释,请告诉我。
答案 1 :(得分:1)
Here's a very good solution I found in Java on Stack Overflow.这是一种在两个数组中找到K和K + 1最小项的方法,其中K是合并数组的中心。
如果你有一个函数来找到两个数组的Kth项,那么找到两者的中位数很容易;
但是你需要一种方法来找到两个列表的Kth项目; (记住我们现在是一个索引)
如果X包含零项,那么X和Y的第K个最小项是Y的第K个最小项
否则,如果K == 2则X和Y的第二个最小项是X和Y中最小的项(min(X [0],Y [0]))
否则;
我。设A为min(长度(X),K / 2)
II。设B为min(长度(Y),K / 2)
III。如果X [A]>然后Y [B]从步骤1中用X,Y'递归,其中Y的所有元素从B到Y的末尾,K'= K-B,否则用X'递归,其中X的所有元素从A到结尾X,Y和K'= K - A
如果我明天找到时间,我将验证此算法是否按照规定在Python中运行并提供示例源代码,它可能会出现一些一对一的错误。
答案 2 :(得分:0)
获取列表A中的中间元素并将其命名为a。将a与列表B中的中心元素进行比较。让我们将它们称为b1和b2(如果B具有奇数长度,则精确分割b的位置取决于您对偶数长度列表的中位数的定义,但无论如何程序几乎相同)。如果b1≤a≤b2则a是合并数组的中值。这可以在恒定的时间内完成,因为它只需要两次比较。
如果a大于b2,那么我们将A的上半部分添加到B的顶部并重复。 B将不再排序,但并不重要。如果a小于b1,那么我们将A的下半部分添加到B的底部并重复。这些将最多迭代log(n)次(如果找到中位数然后停止,当然)。
这可能无法找到中位数。如果是这种情况,则中位数在B中。如果是,则执行与A和B相反的相同算法。这将需要log(m)迭代。总共你将执行最多2 *(log(n)+ log(m))迭代的恒定时间操作,因此你已经按log(n)+ log(m)时间顺序解决了这个问题。
这与iehrlich给出的答案基本相同,但更明确地写出来。
答案 3 :(得分:-2)
是的,这可以做到。给定两个数组A
和B
,在最坏的情况下,您必须首先在A
中执行二进制搜索,然后,如果失败,则在{{1}中进行二进制搜索寻找中位数。在二进制搜索的每一步,您检查当前元素是否实际上是合并的B
数组的中位数。这种检查需要一段时间。
让我们看看为什么这样的检查是不变的。为简单起见,我们假设A+B
是一个奇数,并且两个数组中的所有数字都不同。您可以稍后通过应用通常的中值定义方法(即,如何计算包含重复项的数组的中位数或具有偶数长度的数组的中值)来消除这些限制。无论如何,鉴于此,我们肯定知道,在合并数组中,实际中位数的右侧和左侧将有|A| + |B|
个元素。在(|A| + |B| - 1) / 2
中的二进制搜索过程中,我们知道数组A
中当前元素x
的索引(让它为A
)。现在,如果i
满足条件x
,B[j] < x < B[j+1]
,那么i + j == (|A| + |B| - 1) / 2
就是您的中位数。
总体复杂度为x
时间和O(log(max(|A|, |B|))
内存。