leetcode-4.寻找两个正序数组的中位数

二分查找


题目详情

给定两个大小分别为 mn的正序(从小到大)数组 nums1nums2。请你找出并返回这两个正序数组的 中位数
算法的时间复杂度应该为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

我的第一种代码(直接解法):

思路:直接合并两个数组,然后sort一下,分情况找中位数

class Solution 
{
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) 
    {
        vector<int> nums;
        int len1=nums1.size(),len2=nums2.size();
        //这里可以用insert来合并两个数组
        for(int i=0;i<len1;++i)
        {
            nums.push_back(nums1[i]);
        }
        for(int j=0;j<len2;++j)
        {
            nums.push_back(nums2[j]);
        }
        sort(nums.begin(),nums.end());
        int len=nums.size();
        if(len%2!=0)
        return nums[len/2];
        else
        {
        //注意这里的结果平均数要强制类型转换成浮点数
        return (double)(nums[len/2-1]+nums[len/2])/2;
        }
    }
};

上面这种解法直接简单能通过,但是复杂度不满足题目要求,题目要求明显是二分查找,太难想了,我看了几遍官方讲解视频后总结出了我的代码:

//看完官方讲解之后自己总结的代码及解释(看完官方题解视频再来看)
class Solution 
{
public:
double findMedianSortedArrays(vector<int>& nums1,vector<int>& nums2)
{
    if (nums1.size() > nums2.size())    //为了方便操作,在较短的的数组上进行大多数操作可以减少大多数情况下的算法耗时
    { 
        vector<int> temp = nums1;
        nums1 = nums2;
        nums2 = temp;
    }
    int m=nums1.size(),n=nums2.size();
    int minI = 0;               //这里也就是nums1划分线的左边位置下标可能的最小值
    int maxI = m;                //最大值
    int halfLen = (m + n + 1) / 2;//官方题解有解释,halfLen即为划分线左右总体的元素个数(+1是因为免去讨论奇偶) 
    while (minI <= maxI)              //二分查找
    {
        int i = (minI + maxI) / 2;  //在可能的范围内用二分查找法来找到正确的数值,这个是中间值
        int j = halfLen - i;        //由nums1的确定位置来得出nums2的位置j
        if (i < maxI && nums2[j - 1] > nums1[i]) //如果i没有向右越界 且 nums2划分线的左边元素大于交叉对应那个nums1元素了(不懂去看官方题解)
        {
            minI = i + 1; // i 这个中间值小了,我们调整 i 的范围(调整划分线)
        }
        else if (i > minI && nums1[i - 1] > nums2[j])//如果i没有向左越界 且 nums1划分线的左边大于交叉对应那个nums2元素了(↑)
        {
            maxI = i - 1; //  i 这个中间值大了,我们调整 i 的范围(调整划分线)
        }
        else //i值是正确的值(划分线满足条件)找出左侧最大值,再分奇偶看看是否需要右侧最小值
        {
            int maxLeft; //找到左侧最大值
            if (i == 0)     //nums1的i左边没有元素了
            {
                maxLeft = nums2[j - 1]; 
            }
            else if (j == 0) //nums2的j左边没有元素了
            {
                maxLeft = nums1[i - 1]; 
            }
            else 
            {
                maxLeft = max(nums1[i - 1], nums2[j - 1]); 
            }
            if ((m + n) % 2 == 1)         //如果是奇数,则中位数就是maxLeft了,直接返回
            { 
                return maxLeft; 
            }

            int minRight; //找到右侧最小值    如果是偶数还需要找到minRight求平均数
            if (i == m)                 //num1的i右边没有元素了
            {
                minRight = nums2[j]; 
            }
            else if (j == n)            //nums2的j右边没有元素了
            {
                minRight = nums1[i]; 
            }
            else 
            { 
                minRight = min(nums2[j], nums1[i]); 
            }

            return (double)(maxLeft + minRight) / 2.0;
        }
    }
    return 0.0;
}
};

涉及知识点:

1.二分查找

二分查找也常被称为二分法或者折半查找,每次查找时通过将待查找区间分成两部分并只取一部分继续查找,将查找的复杂度大大减少。对于一个长度为 O(n) 的数组,二分查找的时间复杂度为 O(log n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ggaoda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值