繁体   English   中英

为什么找到 2 个不同大小的排序数组的中位数需要 O(log(min(n,m)))

[英]Why finding median of 2 sorted arrays of different sizes takes O(log(min(n,m)))

请考虑这个问题:

我们有 2 个不同大小的排序数组,A[n] 和 B[m]; 我已经并实现了一个经典算法,它最多需要 O(log(min(n,m)))。

方法如下:开始将两个数组划分为两组,每组一半(不是两个部分,但两个分区应该具有相同数量的元素)。 前半部分包含来自第一个和第二个数组的一些第一个元素,后半个包含来自第一个和第二个数组的其余(或最后一个)元素。 因为数组可以有不同的大小,所以并不意味着从每个数组中取出一半。 达到一个条件,使得前半部分的每个元素都小于或等于后半部分的每个元素。

请看上面的代码:

double median(std::vector<int> V1, std::vector<int> V2) 
{
    if (V1.size() > V2.size())
    {
        V1.swap(V2);
    };
    int s1 = V1.size();
    int s2 = V2.size();
    int low = 0;
    int high = s1;
    while (low <= high) 
    {
        int px = (low + high) / 2;
        int py = (s1 + s2 + 1) / 2 - px;

        int maxLeftX = (px == 0) ? MIN : V1[px - 1];
        int minRightX = (px == s1) ? MAX : V1[px];

        int maxLeftY = (py == 0) ? MIN : V2[py - 1];
        int minRightY = (py == s2) ? MAX : V2[py];

        if (maxLeftX <= minRightY && maxLeftY <= minRightX) 
        {
            if ((s1 + s2) % 2 == 0) 
            {
                return (double(std::max(maxLeftX, maxLeftY)) + double(std::min(minRightX, minRightY)))/2;
            }
            else 
            {
                return std::max(maxLeftX, maxLeftY);
            }
        }
        else if(maxLeftX > minRightY)
        {
            high = px - 1;
        }   
        else
        {
            low = px + 1;
        }
    }
    throw;
}

尽管该方法非常简单且有效,但我仍然无法说服自己其正确性。 此外我不明白为什么它需要 O(log(min(n,m)) 步骤。

如果有人可以简要解释正确性以及为什么它需要 O(log(min(n,m))) 步骤,那将是很棒的。 即使您可以提供带有有意义解释的链接。

时间复杂度非常简单,您可以在元素较少的数组中进行二分搜索以找到这样的分区,这使您能够找到中位数。 您执行的步骤恰好为 O(log(#elements)),并且由于您的 #elements 恰好为 min(n, m),因此复杂度为 O(log(min(n+m))。

正好有 (n + m)/2 个元素小于中位数,而相同数量的元素更大。 让我们将它们视为两半(让中位数属于您的选择之一)。

您当然可以将较小的数组分成两个子数组,其中一个完全位于前半部分,第二个位于另一半。 但是,您不知道其中任何一个中有多少元素。

让我们选择一些 x - 您对前半部分较小数组中元素数量的猜测。 它必须在 0 到 n 的范围内。 然后你知道,因为正好有 (n + m)/2 个元素小于中位数,你必须从更大的数组中选择 (n+m)/2 - x 个元素。 然后您必须检查该分区是否确实有效。

要检查分区是否良好,您必须检查较小一半中的所有元素是否小于较大一半中的所有元素。 您必须检查是否 maxLeftX <= minRightY 和 maxLeftY <= minRightX (然后左半部分的每个元素都小于右半部分的每个元素)

如果是这样,您就找到了正确的分区。 您现在可以轻松找到您的中位数(它是 max(maxLeftX, maxLeftY))、min(minRightX, minRightY) 或它们的总和除以 2)。

如果不是,您要么从较小的数组中获取了太多元素(maxLeftX > minRightY 的情况),所以下次您必须猜测 x 的较小值,或者它们太少,则您必须猜测 x 的较大值。

为了获得最佳复杂度,始终猜测 x 可能采用的一系列可能值的中间值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM