题目
给定两个大小为 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
详解:
题目要求时间复杂度,在此贴上讲解时间复杂度的一个通俗帖子:https://zhuanlan.zhihu.com/p/50479555,OK那么在这道题中显然不是让我们合并两数组去编写(时间复杂度),在网上查阅一番,学习了用二分法解题。
本题中的二分法如下
较小数part | 较大数part |
---|---|
part1:nums1[0] …nums1[i-1] | part3:nums1[i] …nums1[m-1] |
part2:nums2[0] …nums2[j-1] | part4:nums2[j] …nums2[n-1] |
我们的目的是找好分界点i和j的取值,从而使得part1和part2中的所有元素<part3和part4中的所有元素,且要使part1与part2中元素个数为(m+n+1)/2个(why?为了定位中位数)。
因为有序,显然part1中元素<part3中元素,part2中元素<part4中元素
故现在只需将分界点做调整,使nums1[i-1]<nums1[j]且nums1[j-1]<nums1[i]
这个过程中会遇到的问题:
1.奇偶性
如果你明白上文加粗字的部分,那么奇偶性将不是问题。
(1)若nums1和num2组成的大数组内元素个数是奇数,那么显然中位数应该是第(m+n+1)/2个元素,所以从值最小的part1、part2开始看,显然max{nums1[i-1],nums2[j-1]}即为所求。
(2)若大数组内元素个数是偶数,中位数则为第(m+n+1)/2个与第(m+n+1)/2+1个元素的平均值,即max{nums1[i-1],nums2[j-1]}与min{nums1[i],nums2[j] }的平均值。
2.临界点
遇到临界点怎么办?如果你理解上文加粗部分就会知道,取大取小的部分就可以省了,留下的那个就是你要的
下面开始贴代码(C#)
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
int m=nums1.Length;
int n=nums2.Length;
int maxleft=0;
int minright=0;
int flag=(m+n)%2;
if(m>n)
{
return FindMedianSortedArrays(nums2, nums1);
}
//二分法
int k=(m+n+1)/2;
int start=0;
int end=m;
while(start<=end)
{
int i=(start+end)/2;
int j=k-i;
if(i>start&&nums1[i-1]>nums2[j])//cut需要向前移
{
end=i-1;
}
else if(i<m&&nums2[j-1]>nums1[i])//cut需要向后移
{
start=i+1;
}
else//cut的刚好
{
if(i==0){maxleft=nums2[j-1];}
else if(j==0){maxleft=nums1[i-1];}
else{maxleft=Math.Max(nums1[i-1],nums2[j-1]);}
if(flag==1){return maxleft;}
if(i==m){minright=nums2[j];}
else if(j==n){minright=nums1[i];}
else{minright=Math.Min(nums1[i],nums2[j]);}
return (maxleft+minright)/2.0;
}
}
return 0;
}
}
结果:
执行用时:172ms 击败94.21%用户
内存消耗:26.7M 击败5.05%用户