题目
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)). You may assume nums1 and nums2 cannot be both empty. 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
主要思想
为找到合适的位置划分两个数组:
在nums1和nums2两个数组中分别截取i,j两个长度,将两个数组划分成4部分,使
- 划分后两个数组的左部分的数量和与右部分数量和相等 i+j == (m+n)/2 (奇数偶数情况都满足此式) &&
- 左部分的最大值小于右部分的最小值 max(nums1[i-1], nums2[j-1]) < min(nums1[i], nums2[j]) (由于数组有序)
注: i==0时,nums所有元素被分配到右方; i==nums1.length时,nums所有元素被分到左方
则:
- 当m+n为偶数时,(max(nums1[i-1], nums1[j-1]) + min(nums1[i], nums2[j]))/2对应的位置为中位数的位置
- 当m+n为奇数时,max(nums1[i-1], nums1[j-1])对应的位置为中位数的位置
具体实现
在nums1中二分查找i,对于每个i可以直接计算 j=(m+n)/2-i,然后判断是否满足条件,不满足条件则继续搜索。
主要的麻烦在于处理几个极端情况,i、j为0和长度为最大时。
leetcode题目的解决方案提到需要让i成为较长的数组,上面的处理没用到。
此时算法复杂度为O(log(m)),将数组调换位置,每次搜索较短的数组,能够将算法复杂度降低到O**(log(min(m,n)))。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if (nums1.length == 0)
return (nums2[(nums2.length - 1) / 2] + nums2[nums2.length / 2]) / 2.0;
if (nums2.length == 0) // return median of nums1
return (nums1[(nums1.length - 1) / 2] + nums1[nums1.length / 2]) / 2.0;
int iMin = 0;
int iMax = nums1.length;
int i; // represent begin of right array of divided position, range in [0, nums1.length]
// i = 0 means all nums1 will be put in right
// i = nums1.length means all nums1 will be put in left
while (iMin <= iMax) {
i = (iMin + iMax) / 2;
int j = (nums1.length + nums2.length) / 2 - i; // range in [0, jNum.length]
if (j < 0) {
iMax = i - 1;
continue;
} else if (j > nums2.length) {
iMin = i + 1;
continue;
}
int leftEnd1; // end element of left part in nums1
int leftEnd2;
int rightBegin1;
int rightBegin2;
// nums1 may be all put to right(==0) or left(==nums1.length)
if (i == 0) {
leftEnd1 = Integer.MIN_VALUE; // leftEnd1 is not existed
rightBegin1 = nums1[i];
} else if (i == nums1.length) {
leftEnd1 = nums1[i - 1];
rightBegin1 = Integer.MAX_VALUE;
} else {
leftEnd1 = nums1[i - 1];
rightBegin1 = nums1[i];
}
// nums2 may be all put to right(==0) or left(==nums2.length)
if (j == 0) {
leftEnd2 = Integer.MIN_VALUE;
rightBegin2 = nums2[j];
} else if (j == nums2.length) {
leftEnd2 = nums2[j - 1];
rightBegin2 = Integer.MAX_VALUE;
} else {
leftEnd2 = nums2[j - 1];
rightBegin2 = nums2[j];
}
int maxLeftEnd = Math.max(leftEnd1, leftEnd2);
int minRightBegin = Math.min(rightBegin1, rightBegin2);
if (maxLeftEnd <= minRightBegin) {
if ((nums1.length + nums2.length) % 2 == 0)
return (minRightBegin + maxLeftEnd) / 2.0;
else
return minRightBegin;
} else {
if (j == 0)
iMax = i - 1;
else if (i == 0)
iMin = i + 1;
else if (nums1[i - 1] > nums2[j - 1])
iMax = i - 1;
else
iMin = i + 1;
}
}
return -999;
}
}
public class _4MedianOfTwoSortedArrays {
public static void main(String[] argv) {
int[] nums1 = {1, 3, 4};
int[] nums2 = {2, 5, 8, 10};
Solution solution = new Solution();
double result = solution.findMedianSortedArrays(nums1, nums2);
System.out.println(result);
}
}