lintcode 两个排序数组的中位数

作者: yzawyx0220 | 来源:发表于2017-01-05 17:26 被阅读2251次

    两个排序的数组A和B分别含有m和n个数,找到两个排序数组的中位数,要求时间复杂度应为O(log (m+n))。
    给出数组A = [1,2,3,4,5,6] B = [2,3,4,5],中位数3.5
    给出数组A = [1,2,3] B = [4,5],中位数 3
    题目链接:http://www.lintcode.com/zh-cn/problem/median-of-two-sorted-arrays/#
    这道题的难度等级为困难,难就难在要求时间复杂度为O(logn),那就不能使用普通的遍历来做,那样时间复杂度为O(n)。
    首先在随机位置将A分成两部分:
    left_A | right_A
    A [0],A [1],...,A [i-1] | A [i],A [i + 1],...,A [m-1]
    由于A有m个元素,所以有m + 1种切割(i = 0〜m)。其中:left_A.size() = i,right_A.size() = m-i。注意:当i = 0时,left_A为空,当i = m时,right_A为空。
    同样,在随机位置将B切成两部分:
    left_B | right_B
    B [0],B [1],...,B [j-1] | B [j],B [j + 1],...,B [n-1]
    将left_A和left_B放入一个集合,并将right_A和right_B放入另一个集合。把它们命名为left_part和right_part:
    left_part | right_part
    A [0],A [1],...,A [i-1] | A [i],A [i + 1],...,A [m-1]
    B [0],B [1],...,B [j-1] | B [j],B [j + 1],...,B [n-1]
    如果我们可以确保:
    1)left_part.size() == right_part.size()
    2)max(left_part)<= min(right_part)
    那么我们将{A,B}中的所有元素划分为两个长度相等的部分,一个部分总是大于另一个部分。然后中值=(max(left_part)+ min(right_part))/ 2。
    为了确保这两个条件,只需要确保:

    (1)i + j == m-i + n-j(或:m-i + n-j + 1)
    如果n> = m,我们只需要设置:i = 0〜m,j =(m + n + 1)/ 2-i
    (2)B [j-1] <= A [i],A [i-1] <= B [j]
    为什么一定要n> = m?因为必须确保j是合法索引,因为0 <= i <= m和j =(m + n + 1)/ 2-i。如果n <m,则j可以是负数,这将导致错误的结果。

    在[0,m]中搜索i,找到一个切分点i(j =(m + n + 1)/ 2-i):
    使得B [j-1] <= A [i]和A [i-1] <= B[j]。
    我们可以按照以下步骤进行搜索:
    <1>设置imin = 0,imax = m,然后开始搜索[imin,imax]
    <2>设置i =(imin + imax)/ 2,j =(m + n + 1)/ 2-i
    <3>现在left_part.size() == right_part.size()。而且只有3种情况:
    (1) B[j-1] <= A [i]和A [i-1] <= B [j]
    意味着找到了切分点i,停止搜索。
    (2) B[j-1]> A [i]
    意味着A [i]太小。必须调整i得到B [j-1] <= A [i]。而i只能增加不能减小,因为当i减小时j将增加,因此,B [j-1]增加并且A [i]减小,永远不会满足。所以必须增加i。也就是说,调整搜索范围为[i + 1,imax]。因此,imin = i + 1和然后回到第<2>步。
    (3) A [i-1]> B [j]
    意味着A [i-1]太大,必须减少i得到A [i-1] <= B [j]。因此,设置imax = i-1然后回到第<2>步。
    当找到切分点i时,中值为:
    max(A [i-1],B [j-1])(当m + n是奇数时)
    或(max(A [i-1],B [j-1])+ min(A [i],B [j]))/ 2(当m + n为偶数时)

    现在考虑边值i = 0,i = m,j = 0,j = n,即A [i-1],B [j-1],A [i],B [j]有可能不存在的情况。
    因为要确保max(left_part)<= min(right_part)。因此,如果i和j不是边值(A [i-1],B [j-1]都存在),我们必须检验B [j-1] <= A [i],A [i-1] <= B [j]。但是如果A [i-1],B [j-1],A [i],B [j]中的一些不存在,则不需要检查这两个条件中对应的一个。例如,如果i = 0,则A [i-1]不存在,则不需要检查A [i-1] <= B [j]。所以,需要做的是:
    在[0,m]中搜索i,找到一个切分点i,使得:
    (j == 0或i == m或B [j-1] <= A [i])和
    (i == 0或j == n或A [i-1] <= B [j])
    其中j =(m + n + 1)/ 2-i
    在搜索循环中,只会有三种情况:
    (1)(j == 0或i == m或B [j-1] <= A [i])和
    (i == 0或j = n或A [i-1] <= B [j])
    满足条件停止搜索。
    (2) j> 0和i <m并且B [j-1]> A [i]
    i太小,增加i。
    (3)i> 0和j <n并且A [i-1]> B [j]
    i太大,减少i。
    说的比较多,下面是代码:

    class Solution {
    public:
        /**
         * @param A: An integer array.
         * @param B: An integer array.
         * @return: a double whose format is *.5 or *.0
         */
        double findMedianSortedArrays(vector<int> A, vector<int> B) {
            //int minidx = 0, maxidx = m, i, j, num1, mid = (m + n + 1) >> 1,num2;
            if (A.size() > B.size()) return findMedianSortedArrays(B,A);
            int m = A.size(),n = B.size();
            int imin = 0,imax = m,half_len = (m + n + 1) / 2,i,j,max_of_left,min_of_right;
            while (imin <= imax) {
                i = (imin + imax) / 2;
                j = half_len - i;
                if (i < m && j > 0 && B[j - 1] > A[i]) imin = i + 1;
                else if (i > 0 && j < n && B[j] < A[i - 1]) imax = i - 1;
                else {
                    if (i == 0) max_of_left = B[j - 1];
                    else if (j == 0) max_of_left = A[i - 1];
                    else max_of_left = max(A[i - 1],B[j - 1]);
                    break;
                }
            }
            if ((m + n) % 2 == 1) return max_of_left;
            if (i == m) min_of_right = B[j];
            else if (j == n) min_of_right = A[i];
            else min_of_right = min(A[i],B[j]);
            return (max_of_left + min_of_right) / 2.0;
        }
    };
    
    

    相关文章

      网友评论

        本文标题:lintcode 两个排序数组的中位数

        本文链接:https://www.haomeiwen.com/subject/hypzvttx.html