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)).

思路

该问题其实有多种解法

可以利用归并排序的方法,找到第(m+n)/2个元素

该问题可以转化为在两个排好序的数组中寻找第k小的元素,其具体思路是通过比较A[k/2]和B[k/2]的大小,假如A[k/2] > B[k/2],中位数median不可能出现在区间B[0,k/2]内(证明在此省略),所以该问题就转换为在数组A[0,m]和B[k/2+1,n]内寻找第k/2小的元素,可以通过递归来解决,该方法的时间复杂度为 O(log(m+n))

import java.util.Arrays;
public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int l = (nums1.length + nums2.length + 1) >> 1;
        int r = (nums1.length + nums2.length + 2) >> 1;

        return (this.getKthSortedArrays(nums1, nums2, l) + this.getKthSortedArrays(nums1, nums2, r)) / 2.0;
    }

    public int getKthSortedArrays(int[] l1, int[] l2, int k){
        if(l1.length > l2.length)   return getKthSortedArrays(l2, l1, k);
        if(l1.length == 0)  return l2[k-1];
        if(k == 1)  return Math.min(l1[0], l2[0]);

        int m = l1.length, n = l2.length;
        int i = Math.min(m, k/2);
        int j = Math.min(n, k/2);

        if(l1[i-1] > l2[j-1]){
            return getKthSortedArrays(l1, Arrays.copyOfRange(l2, j, n), k-j);
        }else{
            return getKthSortedArrays(Arrays.copyOfRange(l1, i, m), l2, k-i);
        }
    }
}

下面在介绍种 O(log(min(m,n))) 的方法
给定长度为m的数组A,我们可以把它拆分为两部分

{ A[0], A[1], ... , A[i - 1] } | { A[i], A[i + 1], ... , A[m - 1] }

右边的元素要大于左边的元素,左边元素个数为i,右边元素个数为m-i
其实有m+1种拆分方法 (i取值范围为0~m)

同样我们也可以用同样的方法拆分数组B

{ B[0], B[1], ... , B[j - 1] } | { B[j], B[j + 1], ... , B[n - 1] }

我们把数组A和B的左半部分组合成集合LeftPart,其他组合成RightPart

            LeftPart           |            RightPart 
{ 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. LeftPart's length == RightPart's length (or RightPart's length + 1)
2. All elements in RightPart are greater than elements in LeftPart.

这样我们就把数组A和B中的元素拆分为长度相同的两部分,并且右边元素要大于左边元素,接下来中位数可以很容易找到

要是上面两个条件成立,我们需要保证

1. i + j == m - i + n - j (or: m - i + n - j + 1)

     if n >= m, we just need to set: 

       i = 0 ~ m, j = (m + n + 1) / 2 - i

2. B[j - 1] <= A[i] and A[i - 1] <= B[j]

     considering edge values, we need to ensure:

       (j == 0 or i == m or B[j - 1] <= A[i]) and 

           (i == 0 or j == n or A[i - 1] <= B[j])

所以我们只需要

Search i from 0 to m, to find an object "i" to meet condition (1) and (2) above.

我们是否可以通过二分查找来解决,怎样实现?
假如B[j0-1] > A[i0],则目标ix不可能出现在区间[0,i0]中

Because if ix < i0, then jx = (m + n + 1) / 2 - ix > j0, 

then B[jx - 1] >= B[j0 - 1] > A[i0] >= A[ix]. This violates

the condition (2). So ix can't be less than i0.

同样当A[io-1] > B[j0]时,目标ix不可能出现在区间[i0,m]中
所以我们可以按下面的步骤进行二分查找

1. set imin, imax = 0, m, then start searching in [imin, imax]

2. i = (imin + imax) / 2; j = (m + n + 1) / 2 - i

3. if B[j - 1] > A[i]: continue searching in [i + 1, imax]
   elif A[i - 1] > B[j]: continue searching in [imin, i - 1]
   else: bingo! this is our object "i"

当目标i找到时,中位数为

max(A[i - 1], B[j - 1]) (when m + n is odd)

or (max(A[i - 1], B[j - 1]) + min(A[i], B[j])) / 2 (when m + n is even)
import java.util.Arrays;
public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length){
            return findMedianSortedArrays(nums2, nums1);
        }

        int res1, res2;
        int[] shorta = nums1, longa = nums2;

        int m = shorta.length, n = longa.length;
        int half = (m+n+1)>>1;

        int min = 0, max = m;
        while(min <= max){
            int i = (min + max) >> 1;
            int j = half - i;

            if(j>0 && i<m && shorta[i]<longa[j-1])
                min = i + 1;
            else if(i>0 && j<n && longa[j]<shorta[i-1])
                max = i-1;
            else{
                if(i == 0)
                    res1 = longa[j-1];
                else if(j == 0)
                    res1 = shorta[i-1];
                else
                    res1 = Math.max(shorta[i-1], longa[j-1]);

                if((m+n) % 2 == 1)  return res1;

                if(i == m)
                    res2 = longa[j];
                else if(j == n)
                    res2 = shorta[i];
                else
                    res2 = Math.min(shorta[i], longa[j]);

                return (res1 + res2) / 2.0;
            }
        }
        return 0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值