4. Median of Two Sorted Arrays [LeetCode]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Jacky_chenjp/article/details/75210693

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


题目描述:给定两个有序的整型数组,要求在时间复杂度O(log (m+n))的条件下,找出两个数组的中位数。其中m和n分别为两个数组的长度。


思路分析:这里暂设数组nums1的长度为m,数组nums2的长度为n。

解题之前,先要理解一下中位数概念的由来。中位数可以将原来的集合分成两个大小相等的子集,使得一个子集中的任一个数都大于另一个子集中的任一个数。

在本题中,可以考虑将数组A分成 A[0], A[1], ..., A[i-1]  和  A[i], A[i+1], ..., A[m-1] 左右两个部分,将数组B分成 B[0], B[1], ..., B[j-1]  和  B[j], B[j+1], ..., B[n-1] 左右两个部分。这样的话,只要使得 A左+B左中数的数量与A右+B右中数的数量相等,且满足左边的最大值小于等于右边的最小值,即可求出这两个数组的中位数 = (左边最大值+右边最小值) / 2。

将上面的两个条件形式化表示,即为:

1) i + j == m + n + 1 - i - j (或:m+n-i-j )

2) A[i]>=B[j-1]  &&  A[i-1]<=B[j] 

为了讨论方便,暂取 n >= m,这样就有 j = (m+n+1)/2 - i,且 j 的值不会为负。

ps:这里的 i 和 j 的值分别可以取到 0, m 和 0, n 是为边界值,关于这个的处理比较简单:若 i 或 j == 0 ,则表示左边的最大值就是 B[j-1] 或 A [i-1];如果 i == m 或者 j == n ,则右边的最小值即为 B[j] 或 A[i]。


具体的算法设计:在 [0,m] 区间上二分搜索符合条件的 i (看到题目中要求的 log 量级的时间复杂度,应当可以条件反射地想到二分搜索)。

<1> 设置变量 left = 0, right = m

<2> 令 i = (left + right) / 2, j = (m+n+1)/2 - i

<3> (通过第二步,我们已经使得 左边整数数量==右边整数数量) 那么,下面有三种可能的情况:

    a) A[i] >= B[j-1]  &&  A[i-1] <= B[j] : 此时即找到了符合条件的 i ,可以停止查找,并计算中位数的值了;

    b) A[i] < B[j-1] :此时的 i 太小了,需要增大 i 值,令 left = i + 1。跳回第二步;

    c) A[i-1] > B[j] :此时的 i 太大了,需要减小 i 值,令 right = i - 1。跳回第二步;

ps:因为我们这里计算 j ,半长设的是 m + n + 1,如果 m + n 为奇数,那么此时的中位数就是左边的最大值。


AC的Java代码如下所示:

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        
        int m = nums1.length;
        int n = nums2.length;
        
        if (m>n) 
            return binSearch(nums2, nums1, n, m);
        else 
            return binSearch(nums1, nums2, m, n);
    }
    
    public double binSearch(int[] a, int[] b, int m, int n) {
        
        int left = 0, right = m, halfLen = (m+n+1)/2;
        int maxLeft=0, minRight=0;
        
        // binary search
        while (left<=right) {
            int i = (left+right)/2;
            int j = halfLen - i;
               
            if (i>0 && a[i-1]>b[j]) {
                // the value of i is too large
                right = i-1;
            } else if (i<m && a[i]<b[j-1]) {
                // the value of i is too small
                left = i+1;
            } else {
                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;
                
                if (i==m)
                    minRight = b[j];
                else if (j==n) 
                    minRight = a[i];
                else minRight = Math.min(a[i], b[j]);
                
                break;
            }
        }
        
        return (maxLeft+minRight)/(2.0);
    }
}



猜你喜欢

转载自blog.csdn.net/Jacky_chenjp/article/details/75210693
今日推荐