寻找两个正序数组的中位数

题意:给定两个大小分别为 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;
    }
};
posted @ 2021-04-16 11:16  Tsukinousag1  阅读(89)  评论(0)    收藏  举报