Leetcode:寻找两个正序数组的中位数

news2024/11/16 1:53:37

题目链接:4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

题目分析

1、当只有一个有序数组时,该数组的中位数会将该数组分为两份:左子数组 和 右子数组

2、当有两个有序数组时, 我们仍然可以通过一条分隔线将两个数组分割,要求如下(前面两个是一个条件分开来写的,最后一个是一个条件,我们找到的分割线一共要满足两个条件)

  1. 两数组长度和为偶数时:分割线左右两侧元素个数相同
  2. 两数组长度和为奇数时:分割线左侧元素个数比右侧多一
  3. 分割线左侧的所有元素的数值 <= 分割线右侧所有元素的数值(交叉情况)
  • 不理解为什么要这样设置的,再想想中位数的定义,以及我们提供的数组是什么数组
  • 这样是为了确保中位数一定只与分割线两侧的元素有关,我们需要确定这条红线的位置

3、 假设两个有序数组的长度分别为m和n(这样计算可以保证分割线的第一个条件)

  • m+n为偶数时:分割线左侧元素个数为 = (m + n)/ 2 
  • m+n为奇数时:分割线左侧元素个数为 = (m + n + 1)/ 2 (因为我们之前规定中位线位于分割线左侧,所以分割线左侧元素个数要比右侧元素个数多一)
  • /是向下取整,故m+n为偶数时的计算式也可以变为(m + n + 1)/ 2,因此无论两个有序数组的长度和是奇数还是偶数,它们分割线左侧的元素个数均为(m + n + 1)/ 2

 4、只有一个有序数组时,分割线一定满足左侧所有元素 <= 右侧所有元素,但是在两个不同的有序数组的情况下不一定是这样的,我们需要对分割线进行适当调整(交叉情况)

  • 在代码中我们直接将最短的数组设置为第一个数组,因此不会存在第二个问题 

5、 由于我们需要访问分割线左右两侧的元素,因此如果某个数组过短或者两数组相等时,再去访问分割线两侧元素可能会导致越界访问的问题

  • 一个数组过短

  • 当两个数组长度相等时

补充:

1、分割线在第1个数组右边的第1个元素的下标i = 分割线在第1个数组左边的元素个数

2、分割线在第2个数组右边的第1个元素的下标j = 分割线在第2个数组左边的元素个数

普通版本(二分查找)

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    
		if (nums1.size() > nums2.size())  //保证数组1一定最短
		{
			swap(nums1,nums2);
		}
        int m = nums1.size();
		int n = nums2.size();


        //两个数组分割线左侧所有的元素个数(分割线第一条件)
        int totalLeft = (m+n+1)/2;

        //在第一个数组[0,m]中寻找满足第二条件的分割线:
        //第一个数组分割线左侧的数值 <= 第二个数组分割线右侧的数值 且 第二个数组分割线左侧的数值 <= 第一个数组分割线右侧的数值 
        //nums1[i - 1] <= nums2 [j] && nums2[j - 1] <= nums1[i](分割线第二条件)
        //提示1:分割线在第1个数组右边的第1个元素的下标i = 分割线在第1个数组左边的元素个数
        //提示2:分割线在第2个数组右边的第1个元素的下标j = 分割线在第2个数组左边的元素个数


        int left = 0;//第一个数组的左边界
        int right = m;//第一个数组的右边界
        
        //由于已提前将最短数组固定为nums1,所以在移动查找时候,i只会右移,j只会左移
        //循环查找
        while(left <right)
        {
            int i = (left + right + 1)/ 2;//开始时先取一个中间位置的下标作为第一次的i
            int j = totalLeft - i;//第一个数组分割线左边的数有i个,两个数组分割线左侧的数有totalLeft个,totalLeft - i得到第二个数组分割线左侧的数的个数j
            
            //如果条件不满足就移动缩小判断范围(left右移或者right左移)
            if(nums1[i - 1] > nums2[j]) //如果第一个数组分割线左侧的数值大于第二个数组分割线右侧的数值,right左移一位,即分割线左移
            {
                right = i - 1;//下一轮的搜索区间为[left,i - 1]
            }
            else如果第一个数组分割线左侧的数值小于第二个数组分割线右侧的数值,left向右移动,即分割线右移
            {
                //下一轮的搜索区间为[i,right]
                left = i ;
            }

        }
        //循环结束表示已经在第一个数组中找到了合适的分割线


        int i = left;//i此时表示第一个数组中分割线右侧数值的下标
        int j = totalLeft - i;//j此时表示第二个数组中分割线右侧数值的下标
        int nums1LeftrMax = (i == 0 ? INT_MIN : nums1[i-1]);//两个数组长度相同时,第一个数组的分割线左侧的值不能被使用,第一个数组分割线左侧的数值设为整型最小值
        int nums1RightMin = (i == m ? INT_MAX : nums1[i]);//两个数组长度相同时,第一个数组的分割线右侧的值不能被使用,第一个数组分割线右侧的数值设为整型最大值
        int nums2LeftrMax = (j == 0 ? INT_MIN : nums2[j-1]);//两个数组长度相同时,第二个数组的分割线左侧的值不能被使用,第二个数组分割线左侧的数值设为整型最小值
        int nums2RightMin = (j == n ? INT_MAX : nums2[j]);//两个数组长度相同时,第二个数组的分割线左侧的值不能被使用,第二个数组分割线右侧的数值设为整型最大值

        //到这里,已经获取了两个数组分割线左右两侧的数值


        if((m+n) % 2 == 1) //两数组总长度为奇数时,获取的是两数组分割线左侧两个数的最大值
        {
            return max(nums1LeftrMax,nums2LeftrMax);
        }
        else//两数组总长度为偶数时,获取的是两数组分割线左侧两个数的最大值和分割线右侧两个数的最小值的平均值
        {
            return ((max(nums1LeftrMax,nums2LeftrMax) + min(nums1RightMin,nums2RightMin)) / 2.0);//整数 / 浮点数 = 浮点数,整数 / 整数 = 整数
        }
    }
};

问题1:int right = m; 为什么不是 m-1

        在二分查找中,right 的初始化为 m 而不是 m-1 是因为我们需要包括所有可能的分割线位置,包括数组的末尾。对于一个数组 numsm 是数组的长度,nums[m] 是有效的位置(\0)

  • 初始化 left = 0right = m 意味着我们在 [0, m] 范围内寻找分割线位置。
  • 如果初始化 right = m-1,则会遗漏数组的末尾分割位置,这是不正确的

问题2:/2.0/2 的区别

        在计算中位数时,为什么要使用 /2.0 而不是 /2,这是因为 2.0 是一个浮点数,使用浮点数除法可以确保结果是浮点数,而 /2 是整数除法,会丢失小数部分:

double result = (max(nums1LeftMax, nums2LeftMax) + min(nums1RightMin, nums2RightMin)) / 2.0;
  • /2.0 会进行浮点数除法,确保结果是 double 类型
  • /2 是整数除法,如果被除数是整数,则结果会是整数,丢失小数部分,导致计算不准确

 

~over~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1717366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第5章 锁与进程间通信(3)

目录 5.4 其他IPC机制 5.4.1 信号 5.4.2 管道和套接字 5.5 小结 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 5.4 其他IPC机制 5.4.1 信号 kill命令&#xff1a; 作用&#xff1a;发送指定信号。 信号分为&#xff1a; 传统32个信号。 用于实…

【机器学习】Samba-CoE实现高效推理部署

Samba-CoE&#xff1a;突破AI内存墙&#xff0c;实现高效推理部署 一、引言二、Samba-CoE系统概述三、突破AI内存墙的关键技术流数据流三层内存系统 四、Samba-CoE的推理部署与优化动态模型切换资源优化分配性能加速 五、代码实例与实现细节六、结语 一、引言 随着人工智能技术…

es的总结

es的collapse es的collapse只能针对一个字段聚合&#xff08;针对大数据量去重&#xff09;&#xff0c;如果以age为聚合字段&#xff0c;则会展示第一条数据&#xff0c;如果需要展示多个字段&#xff0c;需要创建新的字段&#xff0c;如下 POST testleh/_update_by_query {…

2024-05-31 blue-VH-driver-问题分析-有状态的服务-状态的处理

摘要: VH的driver对上层提供的接口&#xff0c;是会保持状态。这个状态&#xff0c;可以分为&#xff0c;查询的数据的状态&#xff0c;主要是为了提供翻页查询的功能。另一种状态&#xff0c;就是订阅。 有状态的服务: 状态是什么? 其实从调用方的角度更好的理解&#xff0c…

AIGC绘画设计——Stable Diffusion进阶使用

&#xfeff;本文讲解&#xff0c;模型底模&#xff0c;VAE美化模型&#xff0c;Lora模型&#xff0c;hypernetwork。 文本Stable Diffusion 简称sd 欢迎关注留言&#xff0c;不定期追加更新&#xff01; 使用模型 C站&#xff1a;https://civitai.com/ huggingface&#…

快团团大团长帮卖团长团长如何获得物流查询码?

一、功能说明 团长可自行生成物流查询码&#xff0c;直接将码发给顾客&#xff0c;顾客扫码可查询自己订单的物流状态&#xff01; 用户扫码后&#xff0c;会出现用户在该团长处下单的所有快递订单。团员可查看该订单物流信息、进行退款申请&#xff0c;或直接联系团长。 二…

使用Python爬取华为市场游戏类APP应用

文章目录 1. 写在前面2. 接口分析3. 爬虫开发4. 下载链接获取 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守…

摘下戛纳大奖的《狗阵》,救得了华谊吗?

随着第77届戛纳国际电影节成功落幕&#xff0c;《狗阵》无疑成为了华语电影的最大赢家。 今年的戛纳电影节可以说是华语电影大年&#xff0c;《风流一代》《狗阵》《酱园弄》《九龙城寨之围城》等多部重量级影片亮相戛纳。 但最终抱得奖项而归的只有管虎导演的《狗阵》&#…

长虹55D3P海思平台固件破解

一 、背景 目前网上还没有长虹海思平台智能电视的固件打包解包教程&#xff0c;仅有一个znds的解包&#xff0c;但大佬迟迟没更新打包教程和工具。帖子中也没讲解解包的原理&#xff0c;对于不熟悉海思平台的来说&#xff0c;感觉无从下手。 znds海思解包贴&#xff1a;#长虹…

Vue 2.0使用Vue-count-to给数字添加增长动画

在开发后台管理系统时&#xff0c;时常会遇到数据汇总&#xff0c;为了页面展示更生动&#xff0c;用户体验更好&#xff0c;通常会对汇总的数字加一个逐步递增动画。 实现这个效果一般是用的 Vue-count-to这个插件&#xff0c;这是一款简单好用的一个数字滚动插件&#xff0c;…

3D视觉系统实现自动化上下料操作

在竞争激烈的汽车制造行业&#xff0c;提高生产效率、降低成本并保证产品质量是企业持续发展的关键。特别是在汽车制造过程中&#xff0c;各种零部件的上下料操作占据了大量的生产时间&#xff0c;因此如何实现这些操作的自动化、高效化成为了一个亟待解决的问题。 富唯智能3D视…

157.二叉树:二叉树的右视图(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* Tre…

【C++修行之道】类和对象(二)类的6个默认成员函数、构造函数、析构函数

目录 一、类的6个默认成员函数 二、构造函数 2.1 概念 2.2 特性 2.2.5 自动生成默认构造函数 不进行显示定义的隐患&#xff1a; 2.2.6 自动生成的构造函数意义何在&#xff1f; 两个栈实现一个队列 2.2.7 无参的构造函数和全缺省的构造函数都称为默认构造函数&#x…

pycharm 上一次编辑位置不见了

目录 pycharm2024版 上一次编辑位置不见了&#xff0c;研究发现移到了左下角了&#xff0c;如下图所示&#xff1a; 上一次编辑位置快捷键&#xff1a; pycharm2024版 上一次编辑位置不见了&#xff0c;研究发现移到了左下角了&#xff0c;如下图所示&#xff1a; 上一次编辑…

Minio篇:初识MinIO

1. MinIO快速入门 1.1.MinIO核心概念 下面介绍MinIO中的几个核心概念&#xff0c;这些概念在所有的对象存储服务中也都是通用的。 对象&#xff08;Object&#xff09; 对象是实际的数据单元&#xff0c;例如我们上传的一个图片。 存储桶&#xff08;Bucket&#xff09; 存储…

不同linux账户切换不同的cuda版本

原因 由于服务器中安装了两个版本的cuda&#xff08;cuda10.1和cuda11.1&#xff09;&#xff0c;不同项目可能需要应用不同的cuda版本&#xff0c;但是自己又没有root权限或者只想在使用指定conda环境时改为用指定的cuda版本。总结起来有三种方法&#xff1a; 1、修改软链接指…

原生小程序一键获取手机号

1.效果图 2.代码index.wxml <!-- 获取手机号 利用手机号快速填写的功能&#xff0c;将button组件 open-type 的值设置为 getPhoneNumber--><button open-type"getPhoneNumber" bindgetphonenumber"getPhoneNumber">获取手机号</button> …

Javaweb基础之Cookie会话技术

大家好&#xff0c;这里是教授.F 引入&#xff1a; 我们想在登录一个网站时&#xff0c;能够显示我们上一次的登录时间啊&#xff0c;或者我们在该网站的浏览痕迹。哪这些要怎么做到&#xff1f;我们想&#xff0c;这些数据不可能从服务端给你返回来&#xff0c;因为一旦用户…

Line Worker(流水线工人休闲游戏模板)

您是地狱工厂的流水线工人。您的工作是在产品不断流动的情况下,将有缺陷的产品与合格产品区分开来。通过点击左右键来保留合格产品并丢弃不合格产品。错误太多,您将被解雇!《流水线工人》是一款有趣、轻松、超级休闲的游戏,适合所有年龄段的人! 亮点: - 上瘾的超休闲游戏…

Jvm(一)之栈、堆、方法区

前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入工作的漩涡&#xff0c;忘记了停下脚步&#xff0c;感受周围的世界。让我们一起提醒自己&#xff0c;要适时放慢脚步…