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

写在前面:

题目链接:LeetCode4. 寻找两个正序数组的中位数
编程语言:C++
题目难度:困难

一、题目描述

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

算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:

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

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

二、题目分析&解题思路&代码实现

2.1 归并法

看到这样的描述,大家应该很快想到了归并排序的原理,如果这里对归并排序不太了解的可以参考以下博客:
十大排序算法思路&代码实现(持续更新中)
或者也可以直接看下面的解题思路:
两个有序数组
1 , 3
2 , 4
我们只需要新建一个 vector ,然后分别从两个数组,从头到尾数组元素挨个进行比较小的就插入

        vector<int> vctResult;
        int i = 0;
        int j = 0;
        while(i< nums1.size() && j < nums2.size())
        {
            while((i < nums1.size()) && (j < nums2.size()) && nums1[i] <= nums2[j])//这里一定要注意数组越界问题
            {
            	//小的插入
                vctResult.push_back(nums1[i]);
                i++;
            }
            while((i < nums1.size()) && (j < nums2.size()) && nums2[j] <= nums1[i])
            {
                vctResult.push_back(nums2[j]);
                j++;
            }

        }
        //如果两个数组size 不相等,那么剩下的肯定就是大的数,直接插入即可
        while(i < nums1.size())
        {
            vctResult.push_back(nums1[i]);
            i++;
        }
        while(j < nums2.size())
        {
            vctResult.push_back(nums2[j]);
            j++;
        }

最后构建出一个新的数组:
1 , 2 , 3 ,4
接着我们只需要判断数组的 size 是基数还是偶数即可:

		int mid = (nums1.size() + nums2.size())/2;
        if(vctResult.size()%2==0)
        {
        	//偶数取中间两个 除以 2.0(注意返回值为 double)
            dResult = (vctResult[mid] + vctResult[mid-1])/2.0;
        }
        else
        {
        	//奇数取中间一位即可
            dResult = vctResult[mid];
        }

2.1.1 完整代码示例:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        double dResult = 0.0;
        int mid = 0;
        mid = (nums1.size() + nums2.size())/2;
        vector<int> vctResult;//合并后的新数组
        int i = 0;
        int j = 0;
        while(i< nums1.size() && j < nums2.size())
        {
            while((i < nums1.size()) && (j < nums2.size()) && nums1[i] <= nums2[j])//这里一定要注意数组越界问题
            {
            	//小的插入
                vctResult.push_back(nums1[i]);
                i++;
            }
            while((i < nums1.size()) && (j < nums2.size()) && nums2[j] <= nums1[i])
            {
                vctResult.push_back(nums2[j]);
                j++;
            }

        }
        //如果两个数组size 不相等,那么剩下的肯定就是大的数,直接插入即可
        while(i < nums1.size())
        {
            vctResult.push_back(nums1[i]);
            i++;
        }
        while(j < nums2.size())
        {
            vctResult.push_back(nums2[j]);
            j++;
        }
        if(vctResult.size()%2==0)
        {
        	//偶数取中间两个 除以 2.0(注意返回值为 double)
            dResult = (vctResult[mid] + vctResult[mid-1])/2.0;
        }
        else
        {
        	//奇数取中间一位即可
            dResult = vctResult[mid];
        }
    return dResult;
    }
};

2.1.2 运行结果:

在这里插入图片描述
这里也是通过了,复杂度也是O(m+n) ,但同时也开辟了O(m+n)的空间,空间复杂度较高;

2.1.3 归并优化

这一步还可以再做优化,因为我们只需要合并到 新的数组size > mid 即可,后面的也不需要遍历,也不要再合并了,因此可以,将时间复杂度和空间复杂度都降低一半为:O(1/2(m+n))

代码示例:

class Solution {
public:
    bool isMidFind(vector<int>& vctResult, int& mid, double&dResult,int& size)
    {
        if(vctResult.size() > mid)
        {
            if(size %2 == 0)//偶数取中间两位
            {
                dResult = (vctResult[mid] + vctResult[mid-1])/2.0;
            }
            else//奇数直接取即可
            {
                dResult = vctResult[mid];
            }
            return true;
        }
        else
        {
            return false;
        }

    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        double dResult = 0.0;
        int mid = 0;
        mid = (nums1.size() + nums2.size())/2;
        int size = nums1.size() + nums2.size();
        vector<int> vctResult;//合并后的新数组
        int i = 0;
        int j = 0;
        while(i< nums1.size() && j < nums2.size())
        {
            while((i < nums1.size()) && (j < nums2.size()) && nums1[i] <= nums2[j])//这里一定要注意数组越界问题
            {
            	//小的数插入
                vctResult.push_back(nums1[i]);
                if(isMidFind(vctResult, mid,dResult,size))
                {	
                	//找到了直接return 即可
                    return dResult;
                }
                i++;
            }
            while((i < nums1.size()) && (j < nums2.size()) && nums2[j] <= nums1[i])
            {
                vctResult.push_back(nums2[j]);
                if(isMidFind(vctResult, mid,dResult,size))
                {
                    return dResult;
                }
                j++;
            }

        }
        //如果两个数组size 不相等,那么剩下的肯定就是大的数,直接插入即可
        while(i < nums1.size())
        {
            vctResult.push_back(nums1[i]);
            if(isMidFind(vctResult, mid,dResult,size))
            {
                return dResult;
            }
            i++;
        }
        while(j < nums2.size())
        {
            vctResult.push_back(nums2[j]);
            if(isMidFind(vctResult, mid,dResult,size))
            {
                return dResult;
            }
            j++;
        }

    return dResult;
    }
};
2.1.3.1 运行结果

在这里插入图片描述
可以看到时间和空间复杂度都有所降低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值