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

题目链接: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~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络之快重传和快恢复以及TCP连接与释放的握手

快重传和快恢复 快重传可以让发送方尽早得知丢失消息&#xff0c; 当发送消息M1,M2&#xff0c;M3,M4,M5后,假如消息M2丢失&#xff0c;那么按照算法会发送对M2报文前一个报文M1的重复确认&#xff08;M1正常接受到&#xff0c;已经发送了确认),然后之后收到M4,M5,也会发送两…

内网安全之注册和查看证书

注册证书 如图所示&#xff0c;是 Will Schroeder 和 Lee Christensen 发布的 Certified_Pre-Owned 白皮书里面画的证书注册流程: 从图中我们可以看到&#xff0c;证书注册流程如下&#xff1a; 客户端生成一对公、私钥。客户端生成证书签名请求(CSR&#xff0c;Certificate…

linux系统——性能检测工具glances

在linux系统中&#xff0c;由python开发的glances工具是一个功能强大的性能检测工具 可以通过yum进行安装 安装glances后&#xff0c;进入命令界面 glance支持网站模式&#xff0c;将监控到的数据以网站形式显示出来 这里需要用python包管理命令 使用glances -w开放…

Java集合-List(Collection子接口)及其子类(ArrayList、Vector、LinkedList)

List接口是 Collection接口的子接口。 1、List集合类中数据有序&#xff0c; 即添加顺序和取出顺序有序&#xff0c;而且可以重复。 2、List集合类中每个元素都有其对应的顺序索引&#xff0c;即支持索引。例&#xff0c;list.get(2)&#xff1b;取第三个元素。 3、实现类有很多…

百度地图1

地图的基本操作 百度地图3.0文档 百度地图3.0实例中心 设置地图 centerAndZoom(center: Point, zoom: Number)设初始化地图,center类型为Point时&#xff0c;zoom必须赋值&#xff0c;范围3-19级&#xff0c; // 百度地图API功能var map new BMap.Map("map"); //…

CentOS8搭载正反向解析dns服务器

1.介绍&#xff08;是什么&#xff09; DNS&#xff08;Domain Name System&#xff09;&#xff0c;即域名系统&#xff0c;是一个将域名和 IP 地址相互映射的分布式数据库&#xff0c;它可以将用户输入的域名转换成对应的 IP 地址。DNS 由多个服务器组成&#xff0c;分为多个…

企业想要搭建一个虚拟展厅需要多少钱?

企业搭建虚拟展厅的费用会根据多种因素有所不同&#xff0c;主要包括展厅的类型、规模、功能需求、技术复杂度以及服务商的定价策略等。以下是关于虚拟展厅搭建费用的分点说明和归纳&#xff1a; 一、展厅类型&#xff1a; 1、全景实拍展厅&#xff1a; 利用VR全景拍摄技术还…

结构体中内存的对齐

前言 学C的同学应该知道~ 想精通C语言就不得不面对—指针与内存 续上次指针进阶&#xff0c;这一章我来聊一聊C语言内存对齐的问题 学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的&#x1f601; 思考 #include<stdio.h> typedef struct s1 {char a;char …

【Python】 如何获取 Python 函数的名称作为字符串?

基本原理 在 Python 中&#xff0c;获取函数名称是一个简单但非常有用的技巧&#xff0c;尤其是当你需要动态地引用函数或者在日志、调试中需要函数名称时。Python 提供了几种方法来获取函数的名称。 方法一&#xff1a;使用 __name__ 属性 每个函数对象都有一个 __name__ 属…

【Unity】使用Jenkins实现远程Unity打包

前言 很多时候&#xff0c;我们需要自动打包&#xff0c;比如下班了&#xff0c;我要出一个包明天早上用。比如每天夜里12点&#xff0c;我需要定时出一个稳定包。 这个时候就需要Jenkins了。 1.安装环境 安装 jenkins 之前&#xff0c;需要安装Java 。Java下载网站 ①下载…

校园交友|基于SprinBoot+vue的校园交友网站(源码+数据库+文档)

校园交友网站 目录 基于SprinBootvue的校园交友网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#x…

音视频开发9 FFmpeg 解复用相关整体说明,重要API说明

一&#xff0c;播放器框架 二 常用音视频术语 容器&#xff0f;文件&#xff08;Conainer/File&#xff09;&#xff1a; 即特定格式的多媒体文件&#xff0c; 比如mp4、flv、mkv等。 媒体流&#xff08;Stream&#xff09;&#xff1a; 表示时间轴上的一段连续数据&#xff0…

【技术实操】银河高级服务器操作系统实例分享,数据库日志文件属主不对问题分析

1. 问题现象描述 2023 年 06 月 30 日在迁移数据库过程中&#xff0c;遇到数据库 crash 的缺陷&#xff0c;原因如下&#xff1a;在数据库启动时候生成的一组临时文件中&#xff0c;有 owner 为 root 的文件&#xff0c; 文件权限默认为 640&#xff0c; 当数据库需要使用的时…

C++系列——————类和对象(上)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、面向对象的三大特征二、类的引入2.1类的定义 三.类的访问限定符3.1访问限定符的介绍3.2.访问限定符的使用 四、类的作用域五、类的实例化六、类对象模型6.1…

惠海 H6251L 降压恒压芯片IC 48V 60V 100V 150V 200V 降3.3V 5V 12V 5A大电流 低功耗,动态响应优异

H6251L是一款多样化的高压降压开关控制器&#xff0c;它具备许多引人注目的特性和优势&#xff0c;使其在多个领域都有许多的应用。以下是对H6251L的详细分析&#xff1a; 首先&#xff0c;H6251L具有宽压8V-200V的输入范围&#xff0c;这意味着它可以在电压环境下稳定工作&am…

【康耐视国产案例】智能AI相机联合OSARO为Zenni眼镜实现订单履约自动化

在电商潮流下&#xff0c;Zenni眼镜作为全球领先的在线眼镜零售商&#xff0c;每年销售超过600万副眼镜&#xff0c;却面临着一个独特而复杂的问题——需要通过扫描眼镜盒内的条形码来处理订单。传统手动处理已经到达流程瓶颈&#xff0c;急需一种更加自动化、可扩展的方法。为…

STM32 HAL库USART的接收数据方法实现(STM32Cube_FW_F1_V1.8.5)

目录 概述 1 使用STM32Cube生成项目 1.1 软件版本信息 1.2 配置串口相关参数 1.3 生成工程 2 问题描述 3 解决问题 3.1 修改代码 3.2 编写新的回调函数 4 测试 概述 本文主要介绍STM32 HAL库USART的接收数据方法实现&#xff0c;笔者使用的HAL库为STM32Cube_FW_F1_V1.…

Leetcode刷题笔记6

34. 在排序数组中查找元素的第一个和最后一个位置 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力查找 [1, 2, 3, 3, 3, 4, 5] t 3 从前往后扫描暴力查找&#xff0c;最坏情况下O(N) 优化 利用数组有序的…

【动态规划 组合数学 放球问题】2338. 统计理想数组的数目

本文涉及知识点 动态规划汇总 组合数学汇总 【组合数学 隔板法 容斥原理】放球问题 本题同解 【动态规划】【前缀和】【分组】2338. 统计理想数组的数目 LeetCode2338. 统计理想数组的数目 给你两个整数 n 和 maxValue &#xff0c;用于描述一个 理想数组 。 对于下标从 0…

Unity中模拟生成正态分布的一种方式

using System; using System.Collections; using System.Collections.Generic; using Unity.Mathematics; using UnityEngine;public class MathFunction : MonoBehaviour {private void Start(){//key 范围 0-99 表示 0% 到 99%Dictionary<int,uint> m new Dictionary&…