LeetCode 第4题:两个排序数组的中位数

LeetCode 第4题

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

示例 1:

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

中位数是 2.0

示例 2:

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

中位数是 (2 + 3)/2 = 2.5

解题思路

首先 解释中位数定义,中位数:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。

我把中位数理解成一道线,它将示例1中两个有序数组重组分成了 [1,2], [2,3]两个子集。

假设我们把给定的两个有序集合进行按照中位数的定义进行划分成两个符合要求的子集Left[],Right[]。每个子集长度为 (m+n)/2或者 m+n + 1)/2,这两个子集的元素都是由 nums1 和 nums2 的一些元素组成。                                                                            

为了方便解释,假设 A =nums1[m],B = nums2[n],其中在Left子集中,A有i个元素,B有j个元素,则可以推测出下面

        Left                 |        Right
    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]

由于我们按照中位数定义进行的推测。可以得出以下两个公式

  • len(Left)  =  len(Right)
  • max(Left)  <=  min(Right)

此时 中位数 = ( max(Left) + min(Right) ) / 2;

从这两个公式我们可以推出  i + j = m - i + n - j (或者 m - i + n -j + 1) ;    ==》 if n >= m, i < m; j = (m+n +1) / 2 - i;

解释一下为什么 j = (m+n +1) / 2 - i;当 m + n 为奇数,为了符合定义,

  • len(Left)  =  len(Right) , 需要在集合长度为 min(m,n)中添加一个中位数,即 总长度+1,此时j的数字才不会出错
  • 当 m + n 为偶数时, j = (m + n + 1) / 2  - i,数值不会变化

A[i-1] <= B[j] 以及 B[j - 1] <= A[i]

这里说一句,为了确保 j 不小于0, n 必须不小于m才可以。

这里根据公式开始二叉树递归查找:

假设 imin = 0 , imax = m; 在[ imin , imax]中进行搜索

由于A,B都是有序数组,令 i = ( imin + imax) / 2 ,  j = (m+n +1) / 2 - i;

由于 len(Left)  =  len(Right),则我们会遇到三种情况

当 A[i-1] <= B[j] 以及 B[j - 1] <= A[i] 时, 我们找到了i,问题得解;

当 A[i-1] > B[j] 时,由于 j = (m+n +1) / 2 - i;说明i过大,需要 i--;

当 B[ j - 1 ] > A[i] 时,说明 i 过小,需要i++;

Java Code:

class Solution {
    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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值