LeetCodes刷题总结1——寻找两个正序数组的中位数

题目:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 

示例1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例2:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays

思路:

这道题本身要做出来并不难,直接用两个指针加一个新数组就可以找到中位数。但是有一个关键点不能满足,就是时间复杂度,上述T(n)是O(m+n),而题目要求O(log(m+n)),苦思无果,还是看到一个题解,思想真的神奇。

回归看这道题的本意,中位数,那中位数实际上是什么意思呢?其实是把一组数分成两个相同的部分,左边一定全部小于右边。换言之,当你把一组数分成这两个部分,找到的这个切分点其实就是中位数(偶数自然取两边边缘除2)。对于本题两个有序数组而言,我们实际上要找的是每一个数组的切分点,使得第一个数组的左边一定小于第二个数组的右边,第一个数组的右边也一定大于第二个数组的左边,这个找到的两个切分点再进行操作即可获得两个数组的中位数。比如:

[2 3 | 5]

[1 4 | 7 9]

整体思想是这样,但是会发现实现起来并不容易,这时一个神奇的操作出现了。把所有数组的每一个数加一个#,使之长度一定成为偶数,这样切分的时候‘#’上等于割在2个元素之间,在数字上等于把数字划到2个部分。还要注意,这一步只是思想上这样,真实实现的时候并不会真正给数组加‘#’。

除此以外,还有特殊情况,就是两个数组中一个数组完全大于或完全小于中位数,这样就有四种特殊情况,要作单独处理。

最后,在查找两个切分点的时候使用二分,这样log的复杂度不就有了吗?

代码:

#include <iostream>
#include <vector>
using namespace std;

class Solution
{
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
    {
        int n=nums1.size();
        int m=nums2.size();

        //整体思想实际上是找到两个数组的某个点进行分割,使得这两个点(中位数)能将左右分开

        //保证数组1最短
        if(n>m)
            return findMedianSortedArrays(nums2,nums1);

        //Lmaxi代表第i个数组截取后左边的元素,Rmini代表第i个数组截取后右边的元素
        int Lmax1,Lmax2,Rmin1,Rmin2;

        //ci代表数组i截取的位置
        int c1,c2;
        //对数组1作二分用到的指针,虚拟加了'#'所以数组1是2*n长度
        int low=0,high=2*n;

        while(low<=high)
        {
            c1=(low+high)/2;
            c2=n+m-c1;

            //四种特殊情况的处理
            //比如第一行:数组1整体都在右边了,所以都比中值大,中值在数组2中,简单的说就是数组1割后的左边是空了,所以我们可以假定LMax1 = INT_MIN
            Lmax1 = (c1 == 0) ? INT_MIN : nums1[(c1 - 1) / 2];
            Rmin1 = (c1 == 2 * n) ? INT_MAX : nums1[c1 / 2];
            Lmax2 = (c2 == 0) ? INT_MIN : nums2[(c2 - 1) / 2];
            Rmin2 = (c2 == 2 * m) ? INT_MAX : nums2[c2 / 2];

            //找到Lmax1<Rmin2并且Lmax2<Rmin1的两个点
            if(Lmax1>Rmin2){
                high=c1-1;
            }else if(Lmax2>Rmin1){
                low=c1+1;
            }else
                break;
        }
        return (max(Lmax1,Lmax2)+min(Rmin1,Rmin2))/2.0;
    }
};

int main()
{
    int m,n,e;
    cin>>m>>n;
    vector<int> nums1,nums2;
    for(int i=0; i<m; i++)
    {
        cin>>e;
        nums1.push_back(e);
    }
    for(int i=0; i<n; i++)
    {
        cin>>e;
        nums2.push_back(e);
    }
    double res;
    res=Solution().findMedianSortedArrays(nums1,nums2);
    cout<<res;
    return 0;
}

来源:

力扣icon-default.png?t=LBL2https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/4-xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-shu/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值