当前位置: 首页 > news >正文

LeetCode 热题 100_寻找两个正序数组的中位数(68_4_困难_C++)(二分查找)(先合并再挑选中位数;划分数组(二分查找))

LeetCode 热题 100_寻找两个正序数组的中位数(68_4)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 思路一(先合并再挑选中位数):
        • 思路二(划分数组(二分查找)):
      • 代码实现
        • 代码实现(思路一(先合并再挑选中位数)):
        • 代码实现(思路二(划分数组(二分查找))):
        • 以思路二为例进行调试

题目描述:

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

题解:

解题思路:

思路一(先合并再挑选中位数):

1、因两个数组是有序,可以通过两个指针将两个数组进行合并,在进行合并时每次挑选一个较小的元素进行合并。合并后再挑选中位数,如果合并后元素个数为奇数,则返回中间的元素。如果为偶数则返回中间两个元素的平均数。

2、复杂度分析:
① 时间复杂度:O(m+n),m和n分别为两个有序数组元素的个数。合并两个有序数组的时间复杂度为O(m+n)。查找合并后的中位数时间为O(1)。
② 空间复杂度:O(m+n),需要一个额外的数组来存储合并后的数组。

思路二(划分数组(二分查找)):

1、我们首先考虑一个有序数组取中位数的情况:nums=[2,3,4,6,8,9,10,12,18,20] , n=10。
我们可以将分隔线放在8和9之间:[2,3,4,6,8 | 9 ,10,12,18,20]。(当元素个数为奇数时,左侧元素多1)
将nums拆分成两个数组(分隔线的情况如下):
nums1=[3,8 | 9,10]
nums2=[2,4,6 | 12,18,20]
将nums拆分成两个数组(分隔线的情况如下):
nums1=[2,3,4 |]
nums2=[6,8 | 9,10,12,18,20]
发现其中的规律:
① 分隔线的左侧元素值小于右侧元素值,且当前数组右侧的元素值大于另一个数组左侧的元素值。
② 分隔线左侧的元素个数(两个数组)等于分隔线右侧的元素个数或者左侧比右侧多一个元素。
③ 中位数一定在分隔线的左右两侧元素中选取。

2、通过分析出的规律可得出解题的步骤如下:
① 确定 nums1 中的分隔线(二分查找),再通过分隔线左右两侧元素的个数关系,确定 nums2 中的分隔线。
② 确定分隔线后,若nums1中左侧元素 > nums2中的右侧元素,则nums1中的分隔线需左移减小nums1中左侧元素的值(这里和下方的左侧元素和右侧元素指的是分隔线相邻的元素)。
③ 确定分隔线后,若nums2中左侧元素 > nums1中的右侧元素,则nums1中的分隔线需右移,增大nums1中右侧元素的值。
④ 确定分隔线后,若nums1中左侧元素 <= nums2中的右侧元素,且nums2中左侧元素 <= nums1中的右侧元素。若两个数组元素总和为奇数则输出左侧元素的最大值(nums1和nums2分隔线左侧)。若两个数组元素总和为偶数则输出左侧元素的最大值(nums1和nums2分隔线左侧)+右侧元素的最小值 再除以 2。
官方的视频题解链接(挺不错的)

3、复杂度分析
① 时间复杂度:O(logmin(m,n))),其中 m 和 n 分别是数组 nums1和 nums2 的长度,只对其中较小的数组进行二分查找。
② 空间复杂度:O(1)。

代码实现

代码实现(思路一(先合并再挑选中位数)):
class Solution1 {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {// 初始化指针 i, j 用于遍历 nums1 和 nums2,k 用于遍历合并后的数组 mergeint i = 0, j = 0, k = 0;// 创建一个合并后的数组 merge,其大小为 nums1 和 nums2 长度之和vector<int> merge(nums1.size() + nums2.size());// 合并两个已排序的数组 nums1 和 nums2 到 merge 数组中while (i < nums1.size() && j < nums2.size()) {// 比较 nums1 和 nums2 中当前元素的大小,选择较小的元素放入 merge 数组if (nums1[i] <= nums2[j]) {merge[k++] = nums1[i++]; // 将 nums1 的当前元素放入 merge 中} else {merge[k++] = nums2[j++]; // 将 nums2 的当前元素放入 merge 中}}// 如果 nums1 中还有剩余的元素,继续加入 merge 数组while (i < nums1.size()) {merge[k++] = nums1[i++];}// 如果 nums2 中还有剩余的元素,继续加入 merge 数组while (j < nums2.size()) {merge[k++] = nums2[j++];}// 计算合并后数组的中位数索引int mid = (nums1.size() + nums2.size()) / 2;// 如果合并后的数组长度为奇数,中位数就是中间的那个元素if ((nums1.size() + nums2.size()) % 2 == 1) {return double(merge[mid]); // 返回 merge[mid],直接返回该值} else {// 如果合并后的数组长度为偶数,中位数是中间两个数的平均值return double(merge[mid - 1] + merge[mid]) / 2; // 计算并返回平均值} }
};
代码实现(思路二(划分数组(二分查找))):
class Solution2 {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {// 确保 nums1 是较小的数组,以减少二分查找的次数if (nums1.size() > nums2.size()) {return findMedianSortedArrays(nums2, nums1);}int m = nums1.size();  // nums1 的大小int n = nums2.size();  // nums2 的大小int left = 0, right = m;  // 在 nums1 数组上进行二分查找的左、右边界// 使用二分查找在较小的数组 nums1 中查找合适的分区while (left <= right) {// 计算 nums1 的分区点int partition1 = (left + right) / 2;// 计算 nums2 的分区点,使得左右两部分元素数量相等或相差1int partition2 = (m + n + 1) / 2 - partition1;// 计算分区后的左右部分的最大值和最小值// nums1 左侧最大值int maxLeft1 = (partition1 == 0) ? INT_MIN : nums1[partition1 - 1];// nums1 右侧最小值int minRight1 = (partition1 == m) ? INT_MAX : nums1[partition1];// nums2 左侧最大值int maxLeft2 = (partition2 == 0) ? INT_MIN : nums2[partition2 - 1];// nums2 右侧最小值int minRight2 = (partition2 == n) ? INT_MAX : nums2[partition2];// 判断分区是否有效if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {// 有效分区,计算中位数if ((m + n) % 2 == 0) {// 如果总元素个数是偶数,中位数为左右最大值和最小值的平均值return (max(maxLeft1, maxLeft2) + min(minRight1, minRight2)) / 2.0;} else {// 如果总元素个数是奇数,中位数为左侧的最大值return max(maxLeft1, maxLeft2);}} // 如果 maxLeft1 > minRight2,说明 partition1 太大,需要向左缩小else if (maxLeft1 > minRight2) {right = partition1 - 1;  // 调整右边界} // 如果 maxLeft2 > minRight1,说明 partition1 太小,需要向右扩大else {left = partition1 + 1;  // 调整左边界}}// 如果没有找到合适的中位数,代码逻辑应达到这里,可能代表输入不符合条件return 0.0; // 通过编译需要添加返回值}
};
以思路二为例进行调试
#include<iostream>
#include <vector>
#include <algorithm>
using namespace std;class Solution2 {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {// 确保 nums1 是较小的数组,以减少二分查找的次数if (nums1.size() > nums2.size()) {return findMedianSortedArrays(nums2, nums1);}int m = nums1.size();  // nums1 的大小int n = nums2.size();  // nums2 的大小int left = 0, right = m;  // 在 nums1 数组上进行二分查找的左、右边界// 使用二分查找在较小的数组 nums1 中查找合适的分区while (left <= right) {// 计算 nums1 的分区点int partition1 = (left + right) / 2;// 计算 nums2 的分区点,使得左右两部分元素数量相等或相差1int partition2 = (m + n + 1) / 2 - partition1;// 计算分区后的左右部分的最大值和最小值// nums1 左侧最大值int maxLeft1 = (partition1 == 0) ? INT_MIN : nums1[partition1 - 1];// nums1 右侧最小值int minRight1 = (partition1 == m) ? INT_MAX : nums1[partition1];// nums2 左侧最大值int maxLeft2 = (partition2 == 0) ? INT_MIN : nums2[partition2 - 1];// nums2 右侧最小值int minRight2 = (partition2 == n) ? INT_MAX : nums2[partition2];// 判断分区是否有效if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {// 有效分区,计算中位数if ((m + n) % 2 == 0) {// 如果总元素个数是偶数,中位数为左右最大值和最小值的平均值return (max(maxLeft1, maxLeft2) + min(minRight1, minRight2)) / 2.0;} else {// 如果总元素个数是奇数,中位数为左侧的最大值return max(maxLeft1, maxLeft2);}} // 如果 maxLeft1 > minRight2,说明 partition1 太大,需要向左缩小else if (maxLeft1 > minRight2) {right = partition1 - 1;  // 调整右边界} // 如果 maxLeft2 > minRight1,说明 partition1 太小,需要向右扩大else {left = partition1 + 1;  // 调整左边界}}// 如果没有找到合适的中位数,代码逻辑应达到这里,可能代表输入不符合条件return 0.0; // 通过编译需要添加返回值}
};int main(int argc, char const *argv[])
{vector<int> nums1={1,2};vector<int> nums2={3,4};Solution2 s2;cout<<s2.findMedianSortedArrays(nums1,nums2);return 0;
}

寻找两个正序数组的中位数(68_4)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

相关文章:

LeetCode 热题 100_寻找两个正序数组的中位数(68_4_困难_C++)(二分查找)(先合并再挑选中位数;划分数组(二分查找))

LeetCode 热题 100_寻找两个正序数组的中位数&#xff08;68_4&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;先合并再挑选中位数&#xff09;&#xff1a;思路二&#xff08;划分数组&#xff08;二分查找…...

Java多线程与高并发专题——深入ReentrantReadWriteLock

深入ReentrantReadWriteLock 读写锁出现原因 synchronized和ReentrantLock都是互斥锁。如果说有一个操作是读多写少的&#xff0c;还要保证线程安全的话。如果采用上述的两种互斥锁&#xff0c;效率方面很定是很低的。在这种情况下&#xff0c;咱们就可以使用ReentrantReadWr…...

【Python 语法】算法合集

查找二分查找代码大 O 表示法 广度优先搜索代码 狄克斯特拉算法 递归递归调用栈 分而治之&#xff08;divide and conquer&#xff0c;D&C&#xff09;贪心教室调度问题背包问题集合覆盖问题 动态规划背包问题旅游行程最优化 遇到问题时&#xff0c; 如果不确定该如何 高效…...

[STM32]从零开始的STM32 BSRR、BRR、ODR寄存器讲解

一、前言 学习STM32一阵子以后&#xff0c;相信大家对STM32 GPIO的控制也有一定的了解了。之前在STM32 LED的教程中也教了大家如何使用寄存器以及库函数控制STM32的引脚从而点亮一个LED&#xff0c;之前的寄存器只是作为一个引入&#xff0c;并没有深层次的讲解&#xff0c;在教…...

C++ ++++++++++

初始C 注释 变量 常量 关键字 标识符命名规则 数据类型 C规定在创建一个变量或者常量时&#xff0c;必须要指定出相应的数据类型&#xff0c;否则无法给变量分配内存 整型 sizeof关键字 浮点型&#xff08;实型&#xff09; 有效位数保留七位&#xff0c;带小数点。 这个是保…...

C# 牵手DeepSeek:打造本地AI超能力

一、引言 在人工智能飞速发展的当下&#xff0c;大语言模型如 DeepSeek 正掀起新一轮的技术变革浪潮&#xff0c;为自然语言处理领域带来了诸多创新应用。随着数据隐私和安全意识的提升&#xff0c;以及对模型部署灵活性的追求&#xff0c;本地部署 DeepSeek 成为众多开发者和…...

phpstudy安装教程dvwa靶场搭建教程

GitHub - digininja/DVWA: Damn Vulnerable Web Application (DVWA) Dvwa下载地址 Windows版phpstudy下载 - 小皮面板(phpstudy) 小皮下载地址 1选择windows 版本&#xff0c;点击立即下载 下载完成&#xff0c;进行解压&#xff0c;注意不要有中文路径 点击.exe文件进行安装…...

最新版本SpringAI接入DeepSeek大模型,并集成Mybatis

当时集成这个环境依赖冲突&#xff0c;搞了好久&#xff0c;分享一下依赖配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…...

FastAPI 学习笔记

简介&#xff1a; FastAPI 是一个用于构建 API 的现代、快速&#xff08;高性能&#xff09;的 web 框架&#xff0c;使用 Python 并基于标准的 Python 类型提示。 关键特性: 快速&#xff1a;可与 NodeJS 和 Go 并肩的极高性能&#xff08;归功于 Starlette 和 Pydantic&…...

Elasticsearch:过滤 HNSW 搜索,快速模式

作者&#xff1a;来自 Elastic Benjamin Trent 通过我们的 ACORN-1 算法实现&#xff0c;探索我们对 Apache Lucene 中的 HNSW 向量搜索所做的改进。 多年来&#xff0c;Apache Lucene 和 Elasticsearch 一直支持使用 kNN 查询的过滤搜索&#xff0c;允许用户检索符合指定元数据…...

华为hcia——Datacom实验指南——STP工作基本原理及STP/RSTP基本功能配置

什么时候需要用到STP 在二层交换网络中&#xff0c;为了避免环路产生。 什么是STP STP生成树协议&#xff0c;是用来在冗余链路上消除二层环路。在众多交换机中&#xff0c;需要设置出一个根桥&#xff0c;其余的交换机称为非根桥&#xff0c;根桥是整个交换网络的核心&…...

Vue核心知识:动态路由实现完整方案

在Vue中实现动态路由&#xff0c;并结合后端接口和数据库表设计&#xff0c;是一个复杂的项目&#xff0c;需要多个技术栈和步骤的配合。以下将详细描述整个实现过程&#xff0c;包括数据库设计、后端接口设计、前端路由配置以及如何实现动态路由的功能。 目录 一、需求分析二…...

【Maui】系统找不到指定的文件Xamarin.Android.Aapt2.targets

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI&#xff0c;可从单个共享代码库开发可在 And…...

通过返回的key值匹配字典中的value值

需求 页面中上面搜索项有获取字典枚举接口&#xff0c;table表格中也有根据key匹配字典中的value 方案一 需要做到的要求 这里上面下拉列表是一个组件获取的字典&#xff0c;下面也是通过字典匹配&#xff0c;所以尽量统一封装一个函数&#xff0c;每个组件保证最少变动tabl…...

【Linux第一弹】Linux基础指令(上)

目录 1.ls指令 1.1 ls使用实例 2.pwd指令 3.cd指令 3.1 cd使用实例 4.touch指令 4.1touch使用实例 5.mkdir指令 5.1mkdir使用实例 6.rmdir指令和rm指令 6.1 rmdir指令使用实例->: 6.2 rm指令使用实例 7.man指令 8.cp指令 8.1 cp 使用实例 9.mv指令 9.1mv使用…...

GitCode 助力 JeeSite:开启企业级快速开发新篇章

项目仓库&#xff08;点击阅读原文链接可直达前端仓库&#xff09; https://gitcode.com/thinkgem/jeesite 企业级快速开发的得力助手&#xff1a;JeeSite 快速开发平台 JeeSite 不仅仅是一个普通的后台开发框架&#xff0c;而是一套全面的企业级快速开发解决方案。后端基于 …...

OpenCV计算摄影学(3)CUDA 图像去噪函数fastNlMeansDenoising()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 使用非局部均值去噪算法&#xff08;Non-local Means Denoising algorithm&#xff09;执行图像去噪&#xff0c;该算法来源于 http://www.ipol.…...

【react】快速上手基础教程

目录 一、React 简介 1.什么是 React 2.React 核心特性 二、环境搭建 1. 创建 React 项目 2.关键配置 三、核心概念 1. JSX 语法 表达式嵌入 样式处理 2. 组件 (Component) 3. 状态 (State) 与属性 (Props) 4. 事件处理 合成事件&#xff08;SyntheticEvent) 5. …...

leaflet扩展插件esri-leaflet.js

esri-leaflet.js是一个开源的JavaScript库&#xff0c;它允许开发者在Leaflet地图上轻松地使用Esri的服务&#xff0c;如ArcGIS Online和ArcGIS Server的图层。以下是对esri-leaflet.js插件的详细介绍&#xff1a; 一、主要功能 esri-leaflet.js的主要功能是将Esri的地图服务…...

electron-builder打包时github包下载失败【解决办法】

各位朋友们&#xff0c;在使用electron开发时&#xff0c;选择了electron-builder作为编译打包工具时&#xff0c;是否经常遇到无法从github上下载依赖包问题&#xff0c;如下报错&#xff1a; Get "https://github.com/electron/electron/releases/download/v6.1.12/ele…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4&#xff0c;后7...