Fork me on GitHub

Median of Two Sorted Arrays

今天的题目是:

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

翻译一下:有两个分别排好序的数组num1和num2,大小分别为m和n。找到这两个数组合并后的中位数。时间复杂度应该为O(log(m+n))。

第一种解法:方法是首先排好序(排序只需要排到一半),然后找到中位数。

package com.test;

public class Median {
    
    @org.junit.Test
    public void test(){
        int[] a = {1,4,6};
        int[] b = {2,6,8};
        System.out.println( "中位数为" + getMedian(a,b));
    }
    
    public double getMedian(int[] arrayA,int[] arrayB){
        int lengthA = arrayA.length;
        int lengthB = arrayB.length;
        int halfLength = (lengthA + lengthB) / 2 + 1;
        int[] newArray = new int[halfLength];
        int i = 0,j = 0,k = 0;
        while( i < lengthA && j < lengthB && k < halfLength){
            if(arrayA[i] <= arrayB[j]){
                newArray[k++] = arrayA[i++];
            }else{
                newArray[k++] = arrayB[j++];
            }
        }
        while(i < lengthA && k < halfLength){
            newArray[k++] = arrayA[i++];
        }
        while(j < lengthB && k < halfLength){
            newArray[k++] = arrayB[j++];
        }
        if((lengthA + lengthB) % 2 == 0){
            return ((double)newArray[k-1] + (double)newArray[k-2])/2;
        }else{
            return (double)(newArray[k-1]);
        }
    }
}

时间复杂度:O((m+n)/2) = O(m+n)。

空间复杂度:O((m+n)/2) = O(m+n)。

第二种解法:

首先我们用一个随机数 i 将数组A分成两部分:

既然A有m个元素,那么就有m+1中分法(i = 0 ~ m)。那么就有 len(left_A)= i ,len(right_A) = m - i,注意当 i = 0时,left_A是空的,并且当i = m时,right_A是空的。

对于数组B我们用同样的方式处理:

现在把left_A和left_B放在左边,然后把right_A和right_B放到另一边,我们起名叫left_part和right_part。

 

只要我们把{A,B}分成相等的两部分,并且其中一部分比另一部分大。那么就有

为了确保这两个条件,我们只需要确保

 

注意1:为简单起见,我们假定即使当i = 0,i = m,j = 0,j = n时A[i-1],B[J-1],A[i],B[j]都是合法的。我们在最后在讨论如何处理这些边界值。

注意2:为什么n >= m ?因为我们必须确保 j 是非负的。如果n < m,j也许是负数,这将导致错误的结果。

接下来需要做的是:

package com.test;

public class Median {
    
    @org.junit.Test
    public void test(){
        int[] a = {1,4,6};
        int[] b = {2,6,8};
        System.out.println( "中位数为" + findMedianSortedArrays(a,b));
    }
    
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            if (i < iMax && B[j-1] > A[i]){
                iMin = iMin + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = iMax - 1; // i is too big
            }
            else { // i is perfect
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }
}

结果:

 

 时间复杂度:O(log(min(m,n)))。最开始,查找的范围是[0,m]。并且每次循环查找的范围都会少一半,因此,我们仅仅需要log(m)次循环。每次循环都是常量级操作,因此时间复杂度为O(log(m))。又因为m <= n,因此时间复杂度为O(log(min(m,n)))。

空间复杂度:O(1)。

posted @ 2018-03-28 20:41  爱跑步的星仔  阅读(177)  评论(0编辑  收藏  举报