求两个有序数组的中位数
问题:
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))
大意:
有两个有序的数组nums1和nums2,他们的长度分别为m和n。求两个数组的中位数。时间复杂度为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))的时间复杂度内求出结果。
在O(log n)的时间复杂度内易想到通过2分查找或者分治的思想来解决。
我们可以这样考虑,对于两个数组nums1和nums2,如果m + n是偶数,那么中位数就是nums1和nums2数组合并之后的第(m + n)/2 和 (m + n)/2 + 1 个数的和平均数;如果 m + n是奇数,那么中位数就是(m + n)/2 + 1。所以我们可以将问题一般化,即求合并后的两个素组的第k个数。
令 a + b = k - 1,其中 a是nums1中的第a个数,b是nums2中的第b个数,那么只需要比较nums1[a + 1] 和 nums[b + 1]即可求得第k个数。那么问题的关键就是如何确定a和b的大小。
初始我们令 a = min(k/2, m),b = k - 1 - b (这里我们假设m < n总是成立,假如nums1过小,那么第k个数必在nums2中。) 这里有以下几种情况:
1. k = 1,则sums[a + 1]和sums2[b + 1]中较小的即为所求。
2. sums1[a] < sums2[b],则将sums1中前a个数删除,并令k = k - a,并重新计算a和b。
3. sums1[a] > sums2[b],则将sums2中前b个数删除,并令k = k - b,并重新计算a和b。
4. sums1[a] = sums2[b],则sums1[a + 1]和sums2[b + 1]中较小的即为所求。
代码如下:
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int k = (len1 + len2) / 2;
if ((len1 + len2) % 2 == 0) {
return (double)(findKth(nums1, nums2, 0, 0, len1, len2, k) + findKth(nums1, nums2, 0, 0, len1, len2, k + 1)) / 2;
} else {
return findKth(nums1, nums2, 0, 0, len1, len2, k + 1);
}
}
private int findKth(int[] nums1, int[] nums2, int start1, int start2, int len1, int len2, int k) {
if (len1 > len2) {
//确保len1 < len2
return findKth(nums2, nums1, start2, start1, len2, len1, k);
}
if (len1 == 0) {
return nums2[start2 + k - 1];
}
if (k == 1) {
return Math.min(nums1[start1], nums2[start2]);
}
int p1 = Math.min(k/2, len1);
int p2 = k - p1;
if (nums1[start1 + p1 - 1] < nums2[start2 + p2 - 1]) {
return findKth(nums1, nums2, start1 + p1, start2, len1 - p1, len2, k - p1);
} else if (nums1[start1 + p1 - 1] > nums2[start2 + p2 - 1]) {
return findKth(nums1, nums2, start1, start2 + p2, len1, len2 - p2, k - p2);
} else {
return nums1[start1 + p1 - 1];
}
}