LeetCode 4. 两个排序数组的中位数

题目描述:

题目描述

解题思路

1. 归并法

首先想到的思路就是归并排序中的归并操作,将两个有序的数组进行重组之后O(1)的查找到中位数元素,但是归并的时间复杂度为O(n+m),与要求的O(log(m+ n))相差很多,因此不可行。

2. 分治法

因为时间复杂度要求为O(log(m+n))因此采用的是分治算法这样能保证时间复杂度是log级别。
但是如何进行分治是这道题的难点。
首先需要转化一下思路,求中位数的含义既是:1. 当n为奇数时求(n/2+1)大的数;2. 当n为偶数时求(n/2)大与(n/2+1)大的数。因此这个问题可以转化为求第k大的数的问题。
在两个有序数组中如何求第K大的数?
假设第一个数组中前p项,第二个数组中前q项满足p+q = k-1,那么第k大的数一定是p+1或者q+1位置上的数。
讲到这里就可以通过分治来将问题的规模缩小了。
我们令p=k/2, q = k-p;
1) 如果第一个数组中第p个数 < 第二个数组中第q个数,说明第一个数组中前p个数一定小于第k大数,但是无法确定q位置代表的数字是否比第k个元素大,因此需要继续寻找。此时可以将第一个数组的元素减少p个,k -= p,来缩小范围。
2) 如果第一个数组中第p个数 > 第二个数组中第q个数,同理说明第二个数组中前1个数一定小于第k大数,但是无法确定p位置代表的数字是否比第k个元素大,因此需要继续寻找。此时可以将第二个数组的元素减少q个,k -= q,来缩小范围。
3) 如果第一个数组中第p个数 = 第二个数组中第q个数,说明第K个元素为p或者q位置上的数字,因为他们之前的数字已经到达了k-1。

注意:

  1. k == 1时,说明需要找的数在当前剩下的两个数组的第一个元素中去一个小的;
  2. 当有一个数组的长度为0了,说明只能在另一个数组中取数,因此返回第k大元素即可;
  3. 为了保证判断数组是否为空,始终让第一个数组作为长度较短的数组;

代码实现:

class Solution
{
public:

    double FindK(vector<int>& nums1, vector<int>& nums2,int start1, int start2, int len1, int len2, int k)
    {
        if(len1 > len2)
            return FindK(nums2, nums1, start2, start1, len2, len1, k);
        if(len1 == 0)
            return nums2[start2+k-1]*1.0;
        if(k == 1)
            return min(nums1[start1], nums2[start2])*1.0;

        int p = min(k/2, len1);
        int q = k-p;

        if(nums1[start1+p-1] < nums2[start2+q-1])
            return FindK(nums1, nums2, start1+p, start2, len1-p, len2, k-p);

        if(nums1[start1+p-1] > nums2[start2+q-1])
            return FindK(nums1, nums2, start1, start2+q, len1, len2-q, k-q);

        return nums1[start1+p-1];
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
    {

        int n = nums1.size();
        int m = nums2.size();
        double Median = 0.0;
        int k = ((m+n)>>1) + 1;
        if(m == 1 && n == 1)
        {
            return (nums1[0]+nums2[0])*1.0/2;
        }
        if((n+m)&1)
        {
            Median = FindK(nums1, nums2, 0, 0, n, m, k);
        }
        else
        {
            //cout<<FindK(nums1, nums2, 0, 0, n, m, k-1)<<endl;
            Median = (FindK(nums1, nums2, 0, 0, n, m, k-1)+ FindK(nums1, nums2, 0, 0, n, m, k))/2.0;
        }
        return Median;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值