4. 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n))
思路:
如果不要求复杂度的话这个题特别简单,不管是直接连接后sort还是遍历取中位数都能做出来。但是这个题要求了时间复杂度为log,并且还是两个正序数组。
刷了几天的题之后,现在看到正序数组就想到了二分法,并且二分法的时间复杂度也是log,基本确定这个题是二分解法。题目要求的是中位数,那么就可以先分析问题了。
当m+n为奇数时,那么中位数便是下标为(m+n)/2的那个数;当m+n为偶数时,那么中位数便是下标为(m+n)/2-1,(m+n)/2这两个数的平均数。众所周知中位数前后元素个数相同,两个数组都是正序,但是数字的大小不确定。那么我们其实可以用一条线将两个数组进行分割,前面一组元素的个数需要等于或大1比后面的那一组(大1是因为m+n为奇数的时候直接比较前面一组中两个数组的最后一个元素就可以,因此在确定长度的时候需要向上取整,向上取整之所以可用是因为对于偶数向上取整没有影响,还是之前的结果),并且前面一组的第一个数组最后一个值要小于后面一组第二个数组的第一个值,第二个数组最后一个值要小于后面一组第一个数组的第一个值。那么中位数就是前面一组中两个数组最后一个数的最大值和后面一组中两个数组第一个数的最小值的平均值。
那么问题来了,怎么确定线的位置呢,这就要用到二分法了,通过二分来判断线的位置是否满足预期的要求。
代码:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1=nums1.length;
int len2=nums2.length;
if(len1>len2){
return findMedianSortedArrays(nums2,nums1);
}
int leftlength = (len1+len2+1)/2;
int left=0;
int right=len1;
while(left<right){
int i = left+(right-left+1)/2;
int j = leftlength-i;
if(nums1[i-1]>nums2[j]){
right=i-1;
} else {
left=i;
}
}
int i=left;
int j=leftlength-i;
int nums1leftmax= i==0?Integer.MIN_VALUE:nums1[i-1];
int nums1rightmin= i==len1?Integer.MAX_VALUE:nums1[i];
int nums2leftmax= j==0?Integer.MIN_VALUE:nums2[j-1];
int nums2rightmin= j==len2?Integer.MAX_VALUE:nums2[j];
if((len1+len2)%2==1) return Math.max(nums1leftmax,nums2leftmax);
else return (Math.max(nums1leftmax,nums2leftmax)+Math.min(nums1rightmin,nums2rightmin))/2.0;
}
}