理解两个排序数组的中位数算法

时间:2015-12-05 09:55:18

标签: java arrays algorithm

有两个分别为大小为m和n的排序数组A和B.找到两个排序数组的中位数。总运行时间复杂度应为O(log(m + n))。

我不明白计算aMid和bMid的公式。这些公式背后的逻辑是什么?

int aMid = aLen * k /(aLen + bLen); //一个中间计数

int bMid = k - aMid - 1; // b的中间计数

这是程序的链接。 http://www.programcreek.com/2012/12/leetcode-median-of-two-sorted-arrays-java/][1]

public static double findMedianSortedArrays(int A[], int B[]) {
    int m = A.length;
    int n = B.length;

    if ((m + n) % 2 != 0) // odd
        return (double) findKth(A, B, (m + n) / 2, 0, m - 1, 0, n - 1);
    else { // even
        return (findKth(A, B, (m + n) / 2, 0, m - 1, 0, n - 1) 
            + findKth(A, B, (m + n) / 2 - 1, 0, m - 1, 0, n - 1)) * 0.5;
    }
}

public static int findKth(int A[], int B[], int k, 
    int aStart, int aEnd, int bStart, int bEnd) {

    int aLen = aEnd - aStart + 1;
    int bLen = bEnd - bStart + 1;

    // Handle special cases
    if (aLen == 0)
        return B[bStart + k];
    if (bLen == 0)
        return A[aStart + k];
    if (k == 0)
        return A[aStart] < B[bStart] ? A[aStart] : B[bStart];

    int aMid = aLen * k / (aLen + bLen); // a's middle count    
                                      // I AM STUCK HERE

    int bMid = k - aMid - 1; // b's middle count

    // make aMid and bMid to be array index
    aMid = aMid + aStart;
    bMid = bMid + bStart;

    if (A[aMid] > B[bMid]) {
        k = k - (bMid - bStart + 1);
        aEnd = aMid;
        bStart = bMid + 1;
    } else {
        k = k - (aMid - aStart + 1);
        bEnd = bMid;
        aStart = aMid + 1;
    }

    return findKth(A, B, k, aStart, aEnd, bStart, bEnd);
}

我从代码的评论中得到了一些想法,如何计算这些公式,但仍然不明白向某人解释“为什么这些公式”或这些公式背后的逻辑是什么?

对于int aMid = aLen * k /(aLen + bLen); //一个中间数 作为aMid = aLen / 2 - (i)

和k =(aLen + bLen)/ 2, - &gt; 2 =(aLen + bLen)/ k

将值2放在equ(i)

所以aMid = aLen /(aLen + bLen)/ k == aLen * k /(aLen + bLen)

和int bMid = k - aMid - 1; // b的中间计数

aMid + bMid + 1 = k必须满足才能在A [aMid]&gt;时得出结论。 B [bMid]

至于为什么aMid + bMid + 1 = k是重要的:如果A [aMid]大于B [bMid],你知道A中A [aMid]之后的任何元素都不能是第k个元素B中有太多元素低于它(并且会超过k个元素)。你也知道B [bMid]和B中B [bMid]之前的任何元素都不能是第k个元素,因为A中的元素太少而不是它(在B [bMid]之前没有足够的元素)是第k个元素。)

1 个答案:

答案 0 :(得分:2)

正如您已经提到的那样:aMid + bMid + 1 = k必须满足才能得出以下结论:
A[aMid] > B[bMid] bMid我们可以在aMid之前扔掉所有内容,在bMid之后扔掉所有内容, 因为我们知道有aMid + 1 + aMid(包括= kA[aMid]元素小于aMid。因此,我们的中位数在于其余阵列
考虑到这一点,我们首先设置两个中间值bMidIndexOutOfBoundsException并不重要。唯一要注意的是不要让其中一个引起int aMid = 0; int bMid = k - aMid - 1; if(bMid >= bLen) { bMid = bLen - 1; aMid = k - bMid - 1; }

O(log(n+m))

也可以做到这一点。但这需要花费A[0]次,因为在最坏的情况下,我们只会跳过一个元素(aLen + bLen)。 我们想要的是总是扔掉A > B的百分比 在我们的例子中,这是:

  

A&gt; B:k = k - (bMid +1)= k - (k - aMid)= aMid = k *(aLen /(aLen + bLen))
  B> A:k = k - (aMid + 1)= k - (k * aLen /(aLen + bLen))-1 = k *(bLen /(aLen + bLen)) - 1

忽略-1并假设B > A的概率与E(k) = 0.5 * k * (aLen/(aLen + bLen)) + 0.5 * k * (bLen/(aLen + bLen))相同,我们得到:
= 0.5 * k (aLen + bLen)/(aLen + bLen) = 0.5 * k
O(log(n + m))
这意味着我们得到大约k递归调用,直到app.use(express.static(path.join(__dirname, "public"))); app.use(logger('dev')); app.use(bodyParser.json({limit: '50mb'})); app.all('/*', function(req, res, next){ res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS"); res.header("Access-Control-Allow-Headers", "Content-type,Accept,X-Access-Token,X-Key"); if(req.method === 'OPTIONS'){ res.status(200).end(); } else { next(); } }); app.all("/api/v1/*", [require('./middlewares/validateRequest')]); app.use("/", require("./routes")); app.use(function(req, res, next){ var err = new Error("Not found"); err.status = 404; next(err); }); 为0,然后函数停止。