Median of Two Sorted Arrays

来源:互联网 发布:淘宝开店书籍 编辑:程序博客网 时间:2024/06/03 18:03

题目

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 - i2. 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 violatesthe 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 - i3. 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