寻找两个正序数组的中位数
题意:给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请找出并返回这两个正序数组的 中位数
设计 O(log (m+n)) 的算法
原题链接
前天面试的时候导师问我一个看似非常简单的问题,给你一串数组,求第k小的数,直接脱口说快选O(n),然后导师问我你能不能设计不用快排的做法???快选不是没有用Sort吗???
int quick_choose(int a[],int l,int r,int k)
{
if(l==r)
return a[l];
int x=a[l+r>>1],i=l-1,j=r+1;
while(i<j)
{
do i++;while(a[i]<x);
do j--;while(a[j]>x);
if(i<j)
swap(a[i],a[j]);
}
int num=j-l+1;
if(num>=k)
return quick_choose(a,l,j,k);
else
return quick_choose(a,j+1,r,k-num);
}
然后胡扯对顶堆,老师的麦真的一言难尽,我好像题目也没听清楚,对顶堆处理的是动态插入查找定值k的数,老师都说了不用快排?你还扯堆??都是nlogn的
今天做leetcode遇到一题O(logn)的,求中位数,由二分查找选定分界线
最后要注意边界情况
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size()>nums2.size())
return findMedianSortedArrays(nums2,nums1);
//二分查找分割线
int m=nums1.size();
int n=nums2.size();
int left=0,right=m;
int leftnum=(n+m+1)/2;//规定总比左边多一个
while(left<right)
{
int mid=(left+right+1)>>1;//nums1的中位数
//0 1 2 3 4 5
//left=0,right=5 mid=3,注意取mid-1!
// mid-1 | mid
// j-1 | j
int k=nums2[leftnum-mid];
if(nums1[mid-1]<=k)
left=mid;
else
right=mid-1;
}
//left与right最后都指向mid
//边界问题
// 1 | 4 5
// 0 3 | 6
int i=left,j=leftnum-i;
int nums1leftmax= i==0?INT_MIN:nums1[i-1];
int nums1rightmin= i==m?INT_MAX:nums1[i];
int nums2leftmax= j==0?INT_MIN:nums2[j-1];
int nums2rightmin= j==n?INT_MAX:nums2[j];
if((n+m)%2==1)//奇数长度,返回左边最大值
return (double)max(nums1leftmax,nums2leftmax);
else//偶数长度,返回左边最大值和右边最小值的平均值
return (double)(max(nums1leftmax,nums2leftmax)+min(nums1rightmin,nums2rightmin))/2;
}
};