您的位置:首页 > 其它

Median of Two Sorted Arrays

2015-08-05 22:20 295 查看

题目

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))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)))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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: