题目描述:
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
要求:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
来源:力扣(LeetCode)
链接:题目链接
解答方法:由于题目要求在log时间内找出中位数,显然先合并为一个数组然后找中位数,或者使用双指针进行两个数组的扫描,查找中位数的时间均是不符合要求的。一般要求在log时间内完成多半要联系二分法。那么对于该题怎么使用二分法呢?
采用前面的方式我们一次只能排除一个元素,如果要达到二分的时间要求,我们就需要一次排除多个元素。我们可以这样判断。设两个数组分别为nums1[ ], nums2[ ]. 我们要找的假设是第k个元素,那么我们分别在两个数组中寻找k/2个元素,当num1[start1 + k/2 - 1] <= num2[start2 + k/2 - 1]的时候,我们扔掉num1数组当前位置之前的元素,此处start1表示当前还未进行判断的第一个元素(意味着该元素在需要在本次进行判断,所以最后要-1). 否则我们扔掉num2中应该排除的元素。
由于数组元素的长度可能是奇数也可能是偶数,所以寻找中位数还有一个技巧是,我们定义 int k1 = (num1.length + num2.length + 1)/2;int k2 = (num1.length + num2.length + 2)/2; 我们寻找这两个位置的元素,然后加起来除以2.0便是我们需要寻找的中位数。因为当元素长度是奇数的时候k1和k2是相等的。
具体实现代码如下:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if((nums1 == null || nums1.length == 0) && (nums2 == null || nums2.length == 0)){
return 0.0;
}
int m = nums1.length;
int n = nums2.length;
int k1 = (m + n + 1)/2;
int k2 = (m + n + 2)/2;
if(k1 == k2){
return getKthNumber(nums1, 0, m - 1, nums2, 0, n - 1, k1);
}
return (getKthNumber(nums1, 0, m - 1, nums2, 0, n - 1, k1) + getKthNumber(nums1, 0, m - 1, nums2, 0, n - 1, k2))/2.0;
}
public double getKthNumber(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k){
//下标为0代表第一个元素那么为什么需要加1呢?是因为后面判断的需要(当排除一些数的时候,起始位置加1了,如果判断的位置刚好是最末尾的元素,那么start会大于end)
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
if(len1 > len2){//我们始终保持len2>len1,因为这样如果数组中的元素不够第k个的时候,一定是len1不够了
return getKthNumber(nums2, start2, end2, nums1, start1, end1, k);
}
if(len1 == 0) {//说明nums1数组整个都被排除掉了
return nums2[start2 + k - 1];
}
if(k == 1){//递归的出口条件
return Math.min(nums1[start1], nums2[start2]);
}
//计算当前需要判断的数组下标位置,这样计算下标位置的目的是当不够k/2个数的时候会自动指向数组的末尾
int i = start1 + Math.min(len1, k/2) - 1;
int j = start2 + Math.min(len2, k/2) - 1;
if(nums1[i] < nums2[j]){//说明需要扔掉nums1数组中的前i个元素
return getKthNumber(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}else{
return getKthNumber(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
}
}
}