首页 > 编程语言 >C++算法实践04-寻找两个正序数组的中位数

C++算法实践04-寻找两个正序数组的中位数

时间:2024-07-06 19:55:10浏览次数:3  
标签:正序 04 int 中位数 C++ vector 数组 nums1 nums2

一、题目:

给定两个大小分别为 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

二、解答:

1. 暴力破解但是算法的时间复杂度为O(m+n)。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) 
    {
        int m = nums1.size();
        int n = nums2.size();
        vector<int>::iterator it1 = nums2.begin();
        //合并两个数组
        while(it1 != nums2.end())
        {
            //nums1.resize(m+n);
            nums1.push_back(*it1);
            it1++;
        }
        //对合并完成的数组进行排序
        sort(nums1.begin(),nums1.end());
        //偶数情况
        if((m+n)%2 == 0)
        {
            vector<int>::iterator pose1 = nums1.begin();
            int count = (m+n) / 2 - 1;
            pose1 += count;
            double avg = (*pose1 + *(pose1 + 1)) / 2.0;
            return (avg > 0.0) ? avg : 0.00000;
        }
        //奇数情况
        else
        {
            vector<int>::iterator pose2 = nums1.begin();
            int count = (m+n-1)/2;
            pose2 += count;
            return (double)*pose2;
        }
    }
};

2.利用二分法来缩减时间复杂度。

解题思路:

首先这是两个正序数组,我们想要找到中位数也就等价于找到第k小的数。

那么两个数组也是一样的思想,想要找到两个数组合并后的中位数也就等价于找到第k小的数。

假设两个数组的长度分别为m和n,那么中位数也就是第(m+n+1)/2小的数。当两个数组的长度之和为奇数时,我们只需要找到一个第k小的,它的值就是中位数的值。二当两个数组的长度之和为偶数时,那我们就需要找到第k小的数和第k+1小的数,把他们的和除以二就是中位数的值。这个算法的核心思路就是getkth函数,采用递归的思想去不断排除元素从而逼近中位数,递归的终止条件为找到第1小的数。

假设第一个数组为1、3、4、9

第二个数组为1、2、3、4、5、6、7、8、9、10

那么根据k = (m+n+1)/2 = 7

所以我们要找第7小的数。每次都取两个数组的前k/2个,也就是前三个。通过对比两个数组的前三个我们发现4是大于3的,也就是说第二个数组的3是不可能成为第7小的,那么由于数组时正序的,第二个数组的前三个元素就可以删除,从而减少了k/2个元素。

去除了第二个数组的前三个元素后任务也会发生改变,从原来的寻找第7小变成了(7-3=4)第4小的数,那么这一步需要对比的数位4/2 = 2。将两个数组的前两个数中最大的数进行对比,发现5是大于3的,那么第一个数组的前两个数不可能是第4小的数,就可以将第一个数组的前两个数删除。

去除了第一个数组的前两个元素后任务也会发生改变,从原来的寻找第4小变成了(4-2=2)第2小的数,那么这一步需要对比的数位2/2 =1。但此时出现了两个都是4,我们假设第一个的4大于第二个的4,将第二个数组的4删除。

最终我们需要找到第一小的数,也就是来到了递归的判定点,我们只需要取出两个数组的第一个元素进行比对,谁小那么他就是我们要寻找的中位数。

代码:

class Solution {
public:
    double findMedianSortedArrays(std::vector<int>& nums1, std::vector<int>& nums2) {
        int n = nums1.size();
        int m = nums2.size();
        //当n+m为偶数时,left=right
        //当n+m为奇数时,left+1=right
        int left = (n + m + 1) / 2;
        int right = (n + m + 2) / 2;
        
        return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;
    }
    
    int getKth(std::vector<int>& nums1, int start1, int end1, std::vector<int>& nums2, int start2, int end2, int k) {
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        //当第一个数组的长度大于第二个数组的长度,将两个数组进行交换为了后续的运算
        if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);
        //当第一个数组为空时,只需要返回第二个数组中第start2 + k - 1小的数
        if (len1 == 0) return nums2[start2 + k - 1];
        //递归的终止条件
        if (k == 1) return std::min(nums1[start1], nums2[start2]);
        
        int i = start1 + std::min(len1, k / 2) - 1;
        int j = start2 + std::min(len2, k / 2) - 1;
        
        if (nums1[i] > nums2[j]) {
            return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
        } else {
            return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
        }
    }
};

标签:正序,04,int,中位数,C++,vector,数组,nums1,nums2
From: https://blog.csdn.net/qq_51497103/article/details/140234098

相关文章

  • 使用c++实现图形化文件浏览
       代码中使用了SDL2库,需要先安装并正确配置相关的开发环境。还需要添加字体加载和处理的代码,为图方便,省略。#include<iostream>#include<SDL2/SDL.h>#include<SDL2/SDL_image.h>#include<vector>#include<string>#include<filesystem>constintSCREEN......
  • C++题解(3) 信息学奥赛一本通: 1013:温度表达转化 洛谷:B2013 温度表达转化 土豆编程:M
    【题目描述】利用公式 C=5×(F−32)÷9C=5×(F−32)÷9(其中CC表示摄氏温度,FF表示华氏温度)进行计算转化,输入华氏温度FF,输出摄氏温度CC,要求精确到小数点后55位。【输入】输入一行,包含一个实数FF,表示华氏温度。(F≥−459.67)(F≥−459.67)【输出】输出一行,包含一个......
  • day01 初学c++第一章
    目录一、前置代码以及cout打印两条预处理代码:count打印语句:二、符号常量 三、标识符的命名规范四、数据类型 c++中整数类型的表现形式:在c++中,数字存在有符号和无符号之分的c++中实型的表现形式:代码所用函数:c++中字符型的表现形式:基础运算总结:转义字符c++中字......
  • C++开发调试工具:GDB调试,windebug调试,adb调试
    我们在C++开发过程中时常避免不了要调试追踪,一下介绍最主流的三种调试工具:一.GDB调试1.coredump文件:coredump文件是程序异常时系统产生的错误日志文件,即核心转储文件;编译一个debug程序,必须是debug版本,否则无法产生coredump文件;编译命令:g++test.cpp-omytest-g,必须要......
  • C++中的设计模式
    要搞清楚设计模式,首先得要了解UML中的类的一些关系模型。一.UML图中与类的层次关系UML关系:继承关系(泛化关系);组合关系;聚合关系;关联关系;依赖关系;以上关系强度依次减弱。1.继承关系继承关系是最直接的父子关系,如麻雀和老鹰都继承自鸟类,属于子类继承自父类,所以UML中子类实......
  • 详解C++完美转发
    我们先来看折叠规则引用折叠规则在C++中,引用折叠规则的主要目的是为了保证在模板推导过程中,对于参数T&&能够正确地推导出其最终的引用类型,以便进行参数传递时的正确行为。下面是引用折叠规则的总结:左值引用折叠:T&&折叠为T&T&&&折叠为T&这意味着如果一个左值引用......
  • Ubuntu 22.04.4 LTS 安装 php apache LAMP 环境nginx
    1安装php-fpmaptupdateapt-getinstallphp-fpm#配置php-fpm服务启动systemctlenablephp8.1-fpmsystemctlstartphp8.1-fpm#查看服务systemctlstatusphp8.1-fpm#查看版本root@iZbp1g7fmjea77vsqc5hmmZ:~#php-vPHP8.1.2-1ubuntu2.18(cli)(built:......
  • C++语言常见错误分析汇总
    在一个工程里出现两个main函数时3.obj:errorLNK2005:_mainalreadydefinedinfile1.objDebug/HELLO.exe:fatalerrorLNK1169:oneormoremultiplydefinedsymbolsfound这个就是说,你的main函数重定义了。你看看是不是你的工程里面,包含了很多个有main函数的文件?......
  • L1-046 整除光棍(模拟除法)
    这里所谓的“光棍”,并不是指单身汪啦~说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示......
  • L1-048 矩阵A乘以B
    给定两个矩阵A和B,要求你计算它们的乘积矩阵AB。需要注意的是,只有规模匹配的矩阵才可以相乘。即若A有Ra​行、Ca​列,B有Rb​行、Cb​列,则只有Ca​与Rb​相等时,两个矩阵才能相乘。输入格式:输入先后给出两个矩阵A和B。对于每个矩阵,首先在一行中给出其行数R和列数C,随后R行,每行给......