1. 题目描述
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)).
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
2. 解决思路
这道题的难点主要在于要在题目要求的时间复杂度内考虑不同情况下(也可以说是十分复杂的细节),如何高效地利用二分法来解决这个问题(这里之所以用二分法,是因为要找到nums1[]和nums2[]的各自中位数比大小,nums1Unums2的中位数肯定在这两个数之间,这样就砍掉了一半,进而实现二分)。
而在算法实现过程中,主要要考虑两个关键点:
一、假设nums1比nums2短,那么nums1在1,2对应nums2奇数,偶数,甚至2个,都是不同的情况,要各自单独小心处理,把每一个情况都弄清楚,毕竟奇数个和偶数个的中位数计算方法是不一样的,并且数组太短的话一般方法可能会越界。
二、不是每一次都各砍掉一半的!因为这可能改变nums1Unums2的奇偶性,从而导致中位数计算方法改变。安全同时比较有效的做法是,nums1与nums2每次都砍掉相同的长度,也就是nums1的一半。
其他难点可以看代码中的注释说明
3. 完整代码
package findMedianSortedArrays;
import java.util.Arrays;
import java.lang.Math;
class Solution {
public static void main(String[] args){
Solution slu = new Solution();
int nums1[] = {1,3};
int nums2[] = {2,4};
double result = slu.findMedianSortedArrays(nums1 , nums2);
System.out.println("两个排序数组的中位数是:"+result);
}
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length;
int n = B.length;
if (m <= n)
//保证长度短的数组排在前面,方便理解比较
return findMedianAB(A, m, B, n);
return findMedianAB(B, n, A, m);
}
private double findMedianAB(int[] A, int m, int[] B, int n) {
assert(m <= n); //assertion用于保证程序最基本、关键的正确性,对该boolean表达式进行检查
if (m == 0) {
return median(B, n);
}
if (m == 1) {
if (n == 1)
return MO2(A[0], B[0]);
if (n % 2 == 1) {
return (MO3(B[n/2 - 1], B[n/2 +1], A[0]) + B[n/2]) / 2.0;
}
return MO3(B[n/2 - 1], B[n/2], A[0]); //B数组个数为偶数个的情况
}
if (m == 2) { //之所以要单独分析元素个数为1、2的情况,
//是因为使用二分最终减半之后会最终剩下元素个数为1或者2的情况
if (n == 2) {
return MO4(A[0], A[1], B[0], B[1]);
}
if (n % 2 == 1) {
return MO3( B[n/2],
Math.max(A[0], B[n/2 - 1]), //难点
Math.min(A[1], B[n/2 + 1]) );
}
return MO4( B[n/2], B[n/2 - 1],
Math.max( A[0], B[n/2 - 2] ),
Math.min( A[1], B[n/2 + 1] ) );
}
int midA = (m - 1) / 2; //上取整
int midB = (n - 1) / 2;
if (A[midA] <= B[midB]) {
return findMedianAB( Arrays.copyOfRange(A, midA, m), m - midA,
//可以证明整体的下中位数一定不会被删除
//偶数的情况,整体上下中位数也都不会被删除;
//奇数的情况,上下中位数是相等(因为就1个)的)
}
return findMedianAB( Arrays.copyOfRange(A, 0, m - midA), m - midA,
Arrays.copyOfRange(B, midA, n), n - midA );
}
private double MO2(int a, int b) { //考虑两个数组均只有一个元素的情况
return (a + b) / 2.0;
}
private double MO3(int a, int b, int c) {
//考虑A数组只有一个元素而B数组元素为除1以外的奇数个的情况下
return a + b + c - Math.max(a, Math.max(b, c)) - Math.min(a, Math.min(b, c));
} //找到与B数组的中位数求均值(A、B数组和就为偶数个)的第二大的数
private double MO4(int a, int b, int c, int d) {
//依次找到第二大、第三大的数,再求和除以2得到中位数
int max = Math.max( a, Math.max( b, Math.max( c, d ) ) );
int min = Math.min( a, Math.min( b, Math.min( c, d ) ) );
return (a + b + c + d - max - min) / 2.0;
}
private double median(int[] arr, int n) {
if (n == 0)
return Double.NaN; // error
if (n % 2 == 0)
return (arr[n / 2] + arr[n / 2 - 1]) / 2.0;
return arr[n/2];
}
}