题目
给定两个排序过的数组,长度为m、n,找到两个数组的中位数,时间复杂度要求O(log(m+n))。
解答
该题的主要难点在于对时间复杂度的要求,若是没有要求,较为直观的解法是先将两个排序数组合并为一个数组,再计算中位数,显然时间复杂度为O(n+m),不能满足题目要求。观察该题的时间复杂度,有一个log存在,一般需要对半处理的情况时间复杂度里含有log,例如二分法。但是该题的解法很难想到。
leetcode上给了英文解释,将该问题转化为找第k大的数字,k = (m+n)/2。首先假设A,B两个数组的大小大于k/2,然后比较A[k/2-1]和B[k/2-1]两个元素的大小情况。
1.A[k/2-1]<B[k/2-1],说明将A、B数组合并后,A中前k/2个元素都小于第k大的数,可以将其舍去(假设A中前k/2个元素包含第k大的数,则合并A、B中前k/2个元素后,第k大的数不是第k个,因为第k个数为B[k/2-1],矛盾)。
2.A[k/2-1]>B[k/2-1],与第一种情况类似,舍去B中前k/2个元素。
3.A[k/2-1]=B[k/2-1],说明A[k/2-1]就是第k大的数字。
所以可以利用递归的方法不断比较两个数组中第k/2大的数,直到结束。递归结束条件有三个:
1.若A数组为空,直接返回B[k-1]。
2若k为1,返回A[start]和B[start]中较小的数。
3若A[k/2-1]=B[k/2-1],返回A[k/2-1]。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2)
{
int len = nums1.length+nums2.length;
if((len&1)!=0)
return findKth(nums1,0,nums1.length-1,nums2,0,nums2.length-1,len/2+1);
else
return (findKth(nums1,0,nums1.length-1,nums2,0,nums2.length-1,len/2)+findKth(nums1,0,nums1.length-1,nums2,0,nums2.length-1,len/2+1))/2.0;
}
public double findKth(int[]nums1,int start1,int end1,int[] nums2,int start2,int end2,int k)
{
int m = end1-start1+1;
int n = end2-start2+1;
if(m>n)
return findKth(nums2,start2,end2,nums1,start1,end1,k);
if(m==0)
return nums2[k-1];
if(k==1)
return Math.min(nums1[start1],nums2[start2]);
int partA = Math.min(k/2,m);
int partB = k-partA;
if(nums1[start1+partA-1]<nums2[start2+partB-1])
{
return findKth(nums1,start1+partA,end1,nums2,start2,end2,k-partA);
}
else if(nums1[start1+partA-1]>nums2[start2+partB-1])
{
return findKth(nums1,start1,end1,nums2,start2+partB,end2,k-partB);
}
else
return nums1[start1+partA-1];
}
}