寻找排序数组的中位数

寻找排序数组的中位数

描述:

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。

合并方法O(m+n)

最简单的思路,直接将两个数组合并,时间复杂度为O(m+n),然后判断合并后总数为奇数还是偶数,直接找到中位数。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        vector<int> nums;
        int i=0;
        int j=0;
        if (m == 0) 
        {
            if (n % 2 == 0)
                return (nums2[n / 2 - 1] + nums2[n / 2]) / 2.0;
            else
                return nums2[n / 2];
        }
        if (n == 0) 
        {
            if (m % 2 == 0)
                return (nums1[m / 2 - 1] + nums1[m / 2]) / 2.0;
            else
                return nums1[m / 2];
        }
        for(; i<m && j<n;)
        {
            if(nums1[i]<nums2[j])
            {
                nums.push_back(nums1[i]);
                i++;
            }
            else
            {
                nums.push_back(nums2[j]);
                j++;
            }
        }
        while(i<m)
        {
            nums.push_back(nums1[i++]);
        }
        while(j<n)
            nums.push_back(nums2[j++]);
        if((m+n)%2==0)
            return (nums[(m+n) / 2 - 1] + nums[(m+n) / 2]) / 2.0;
        else
            return nums[(m+n)/2];
    }
};

这种方法简单,但是效率不高。

O(k)的方法

不过我们仅仅需要第 k 大的元素,是不需要“排序”这么复杂的操作的。可以用一个计数器, 记录当前已经找到第 m 大的元素了。同时我们使用两个指针 pA 和 pB,分别指向 A 和 B 数组的第 一个元素,使用类似于mergesort的原理,如果数组A当前元素小,那么 pA++,同时 m++;如果数 组B当前元素小,那么 pB++,同时 m++。最终当 m 等于 k 的时候,就得到了我们的答案,O(k) 时 间,O(1) 空间。

O(log(m+n))的方法

假设 A 和 B 的元素个数都大于 k/2,我们将 A 的第 k/2 个元素(即 A[k/2-1])和 B 的第 k/2 个元素(即 B[k/2-1])进行比较,有以下三种情况(为了简化这里先假设 k 为偶数,所得到的结论 对于 k 是奇数也是成立的):
• A[k/2-1] == B[k/2-1]
• A[k/2-1] > B[k/2-1]
• A[k/2-1] < B[k/2-1]
如果 A[k/2-1] < B[k/2-1],意味着 A[0] 到 A[k/2-1] 的肯定在 A∪B 的 topk 元素的范围内,换句话说,A[k/2-1] 不可能大于 A∪B 的第 k 大元素。
因此,我们可以放心的删除 A 数组的这 k/2 个元素。同理,当 A[k/2-1] > B[k/2-1] 时,可 以删除 B 数组的 k/2 个元素。
当 A[k/2-1] == B[k/2-1] 时,说明找到了第 k 大的元素,直接返回 A[k/2-1] 或 B[k/2-1] 即可。
因此,我们可以写一个递归函数。那么函数什么时候应该终止呢?
• 当 A 或 B 是空时,直接返回 B[k-1] 或 A[k-1];
• 当 k=1 是,返回 min(A[0], B[0]);
• 当 A[k/2-1] == B[k/2-1] 时,返回 A[k/2-1] 或 B[k/2-1]
(这一段转载而来)

class Solution {
public:

    int find_kth(vector<int> nums1, int start1, int end1, vector<int> nums2, int start2, int end2, int k)
    {
        //保证m一定是小于等于n的
        int len1 = end1-start1+1;
        int len2 = end2-start2+1;
        if(len1>len2)
            return find_kth(nums2, start2, end2, nums1, start1, end1, k);
        if(len1==0)
            return nums2[start2+k-1];
        if(k==1)
            return min(nums1[start1], nums2[start2]);

        //比较第k/2个元素的大小
        int i = start1 + min(len1, k/2)-1;
        int j = start2 + min(len2, k/2)-1;
        if(nums1[i]>nums2[j])
            return find_kth(nums1, start1, end1, nums2, j+1, end2, k-(j-start2+1));
        else
            return find_kth(nums1, i+1, end1, nums2, start2, end2, k-(i-start1+1));

    }

    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        int m = nums2.size();
        int left = (n+m+1)>>1;
        int right = (n+m+2)>>1;
        return (find_kth(nums1, 0, n-1, nums2, 0, m-1, left)+find_kth(nums1, 0, n-1, nums2, 0, m-1, right))/2.0;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值