给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
思路:将数组切分两部分,将A的左半部分和B的左半部分 形成整个数组的左半部分,A的右半部分和B的右半部分形成整个数组的右半部分,只要保证左半部分的最大值小于右半部分最小值
假设m为A的数组长度 ,i为A 的切分位置(有m+1)个, n为B 的数组长度,j为B 的切分位置(n+1)个
当m+n为偶数时:
1.保证左右两边长度相等: i+j=(m-i)+(n-j)=>j=(m+n)/2-i
2.左边的最大值小于右边的最小值: max(A[i-1],B[j-1])<=min(A[i],B[j])
中位数为 (max(A[i-1],B[j-1])+min(A[i],B[j]))/2
当m+n为奇数时:
1.保证左边比右边长度大于1: i+j=(m-i)+(n-j)+1=>j=(m+n+1)/2-i
2.左边的最大值小于右边的最小值: max(A[i-1],B[j-1])<=min(A[i],B[j])
中位数为左边比右边多的那个数 max(A[i-1],B[j-1])
当m+n为偶数时, (m+n)/2-i=(m+n+1)/2-i,为了统一 j=(m+n+1)/2-i
对于max(A[i-1],B[j-1])<=min(A[i],B[j])这个条件,A[i-1]必小于A[i],B[j-1]<B[j].我们只要保证A[i-1]<=B[j]和B[j-1]<=A[i].
对于A[i-1]>B[j]时,说明i过大,减小 i,
对于B[j-1]>A[i]时,说明i过小,增加 i,
前提都是 i,j 都不在边界上
0<=i<=m, 为了保证0<=j<=n ==> m<=n
当i,j 在边界时:
i=0 ,说明A在切分之后的左半部分没有值,整个数组左半部分值都在B中,左边最大值为B[j-1]
j=0时 , B在切分之后的左半部分没有值,整个数组左半部分值都在A中,左边最大值为A[i-1]。
i=m时 ,右半部分最小值为B[j], j=n时,右半部分最小值为A[i]
最后通过二分法 查找 符合的 i
public double findMedianSortedArrays(int[] A, int[] B){
int m=A.length;
int n=B.length;
if(m>n)
return findMedianSortedArrays(B,A);
int max=m;
int min=0;
int i=0;
int j=0;
while(min<=max){
i=(min+max)/2;
j=(m+n+1)/2-i;
if(i!=0&&j!=n&&A[i-1]>B[j])max=i-1;
else if(j!=0&&i!=m&&A[i]<B[j-1])min=i+1;
else{
int lmax=0,rmin=0;
if(i==0)lmax=B[j-1];
else if(j==0)lmax=A[i-1];
else lmax=Math.max(A[i-1],B[j-1]);
if((m+n)%2==1)
return lmax;
if(i==m)rmin=B[j];
else if(j==n)rmin=A[i];
else rmin=Math.min(A[i],B[j]);
return (lmax+rmin)/2.0;
}
}
return 0.0;
}