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

归并延拓:LeetCode归并排序逆序对问题

前言

欢迎来到我的算法探索博客,在这里,我将通过解析精选的LeetCode题目,与您分享深刻的解题思路、多元化的解决方案以及宝贵的实战经验,旨在帮助每一位读者提升编程技能,领略算法之美。
👉更多高频有趣LeetCode算法题

归并排序(Merge Sort) 是一种经典的分治算法,核心思想是将一个数组分解成更小的子数组,然后再将这些子数组合并成有序的数组。归并排序的步骤如下:

  • 分解: 将待排序的数组不断分割,直到每个子数组只有一个元素。
  • 合并: 从两个已排序的子数组开始,逐一比较元素并将它们合并成一个新的有序数组。

归并排序的时间复杂度为 𝑂(𝑛log(𝑛)),它是一种稳定的排序算法,适用于大规模数据的排序。由于其分治的特性,它的空间复杂度为 𝑂(𝑛),需要额外的存储空间。

虽然归并排序的初衷是排序,但它在处理与排序相关的其他问题时也非常有用。

⚠️注意:归并排序具体实现原理及代码本篇文章不做讲解,默认阅读者已经掌握归并排序并能熟练默写代码。一定要有排序算法基础才能继续往下哦! 归并排序具体实现原理请看:👉这里

原理:归并排序

本篇文章不做详细讲解。
归并排序具体实现原理请看:👉这里

实战:经典例题讲解

LCR 170.交易逆序对的总数

🌵题目描述

在这里插入图片描述

🌼核心思路

其实刚拿到这个题呢,最容易想到的是暴力解法两层for循环

使用两层 for 循环枚举所有的数对,逐一判断是否构成逆序关系。

public class Solution {public int reversePairs(int[] nums) {int res = 0;int n = nums.length;for (int i = 0; i < n - 1; i++) {for (int j = i + 1; j < n; j++) {if (nums[i] > nums[j]) {res++;}}}return res;}
}

提交代码发现超时,如果就这么简单做完也不可能打上困难的标签了😅

接下来看一下比较优雅的做法 (当然也可以用树状数组解决逆序数问题,本篇文章不做讲解)

利用归并排序来计算逆序对是一种经典且高效的做法,核心思想在于利用归并过程中的有序性来快速统计逆序对。在归并排序中,递归地将数组分为左右两部分,而在合并这两部分时,我们可以通过比较元素的大小来判断逆序对的数量。

具体而言,逆序对的计算可以分为三个部分:

  1. 左侧区间内的逆序对。
  2. 右侧区间内的逆序对。
  3. 横跨左右区间的逆序对。

在分割过程中不做任何操作,而是在合并阶段,通过数组的部分有序性,我们能够迅速计算出跨区间的逆序对。尤其是在合并过程中,每当一个左侧元素大于右侧元素时,就能够确定这个左侧元素与右侧区间中剩下的所有元素构成逆序对。因此,排序的过程非常关键,因为只有通过排序,才能利用元素之间的顺序关系有效地计算逆序对,并避免重复计算。

所以就会有两种写法了:

1、计算第1个子区间右侧有多少个数比他小,计算逆序对的个数;
2、计算第2个子区间左侧有多少个数比他大,计算逆序对的个数。

在这里插入图片描述
在这里插入图片描述

注意:两者不能同时计算,否则会计算重复。

🌿代码实现

Java

第一版:计算右侧有多少个数比他小

class Solution {int[] record, temp;public int reversePairs(int[] record) {int n = record.length;temp = new int[n];if (n < 2)return 0;return reversePairs(record, 0, n - 1, temp);}public int reversePairs(int[] record, int left, int right, int[] temp) {if (left >= right)return 0;int mid = left + (right - left) / 2;int leftPairs = reversePairs(record, left, mid, temp);int rightPairs = reversePairs(record, mid + 1, right, temp);// 小优化if (record[mid] < record[mid + 1]) {return leftPairs + rightPairs;}int mergePairs = merge(record, left, mid, right, temp);return leftPairs + rightPairs + mergePairs;}private int merge(int[] a, int left, int mid, int right, int[] temp) {// 定义三个指针int p1 = left;int p2 = mid + 1;int p3 = 0; // 记录辅助数组中的索引int res = 0;while (p1 <= mid && p2 <= right) {if (a[p1] <= a[p2]) {temp[p3++] = a[p1++];res += p2 - (mid + 1);} else {temp[p3++] = a[p2++];}}// 将左边剩余的数据填充到辅助数组中while (p1 <= mid) {temp[p3++] = a[p1++];// 此时p2 = right + 1 所以(right + 1) - (mid + 1)res += right - mid;}// 将右边剩余的数据填充到辅助数组中while (p2 <= right) {temp[p3++] = a[p2++];}// 把临时数组中的数据拷贝到原数组中int t = 0;while (left <= right) {a[left++] = temp[t++];}return res;}
}

第二版:计算左侧有多少个数比他大

class Solution {int[] record, temp;public int reversePairs(int[] record) {int n = record.length;temp = new int[n];if (n < 2)return 0;return reversePairs(record, 0, n - 1, temp);}public int reversePairs(int[] record, int left, int right, int[] temp) {if (left >= right)return 0;int mid = left + (right - left) / 2;int leftPairs = reversePairs(record, left, mid, temp);int rightPairs = reversePairs(record, mid + 1, right, temp);// 小优化if (record[mid] < record[mid + 1]) {return leftPairs + rightPairs;}int mergePairs = merge(record, left, mid, right, temp);return leftPairs + rightPairs + mergePairs;}private int merge(int[] a, int left, int mid, int right, int[] temp) {// 定义三个指针int p1 = left;int p2 = mid + 1;int p3 = 0; // 记录辅助数组中的索引int res = 0;while (p1 <= mid && p2 <= right) {if (a[p1] <= a[p2]) {temp[p3++] = a[p1++];} else {temp[p3++] = a[p2++];res += mid + 1 - p1;}}// 将左边剩余的数据填充到辅助数组中while (p1 <= mid) {temp[p3++] = a[p1++];}// 将右边剩余的数据填充到辅助数组中while (p2 <= right) {temp[p3++] = a[p2++];// 此时p1 = mid + 1 所以也可以不写res// res += mid + 1 - p1;}// 把临时数组中的数据拷贝到原数组中int t = 0;while (left <= right) {a[left++] = temp[t++];}return res;}
}
Python

第一版:计算右侧有多少个数比他小

class Solution(object):def reversePairs(self, record):n = len(record)temp = [0] * nif n < 2:return 0return self.reversePairsHelper(record, 0, n - 1, temp)def reversePairsHelper(self, record, left, right, temp):if left >= right:return 0mid = left + (right - left) // 2leftPairs = self.reversePairsHelper(record, left, mid, temp)rightPairs = self.reversePairsHelper(record, mid + 1, right, temp)# 小优化if record[mid] < record[mid + 1]:return leftPairs + rightPairsmergePairs = self.merge(record, left, mid, right, temp)return leftPairs + rightPairs + mergePairsdef merge(self, record, left, mid, right, temp):p1 = leftp2 = mid + 1p3 = 0res = 0while p1 <= mid and p2 <= right:if record[p1] <= record[p2]:temp[p3] = record[p1]p3 += 1p1 += 1res += p2 - (mid + 1)else:temp[p3] = record[p2]p3 += 1p2 += 1while p1 <= mid:temp[p3] = record[p1]p3 += 1p1 += 1res += right - midwhile p2 <= right:temp[p3] = record[p2]p3 += 1p2 += 1t = 0while left <= right:record[left] = temp[t]left += 1t += 1return res
C++

第一版:计算右侧有多少个数比他小

class Solution {
public:int reversePairs(vector<int>& record) {int n = record.size();vector<int> temp(n);if (n < 2)return 0;return reversePairsHelper(record, 0, n - 1, temp);}private:int reversePairsHelper(vector<int>& record, int left, int right, vector<int>& temp) {if (left >= right)return 0;int mid = left + (right - left) / 2;int leftPairs = reversePairsHelper(record, left, mid, temp);int rightPairs = reversePairsHelper(record, mid + 1, right, temp);// 小优化if (record[mid] < record[mid + 1]) {return leftPairs + rightPairs;}int mergePairs = merge(record, left, mid, right, temp);return leftPairs + rightPairs + mergePairs;}int merge(vector<int>& record, int left, int mid, int right, vector<int>& temp) {int p1 = left;int p2 = mid + 1;int p3 = 0;int res = 0;while (p1 <= mid && p2 <= right) {if (record[p1] <= record[p2]) {temp[p3++] = record[p1++];res += p2 - (mid + 1);} else {temp[p3++] = record[p2++];}}while (p1 <= mid) {temp[p3++] = record[p1++];res += right - mid;}while (p2 <= right) {temp[p3++] = record[p2++];}int t = 0;while (left <= right) {record[left++] = temp[t++];}return res;}
};

结语

如果您渴望探索更多精心挑选的高频LeetCode面试题,以及它们背后的巧妙解法,欢迎您访问我的博客,那里有我精心准备的一系列文章,旨在帮助技术爱好者们提升算法能力与编程技巧。

👉更多高频有趣LeetCode算法题

在我的博客中,每一篇文章都是我对算法世界的一次深入挖掘,不仅包含详尽的题目解析,还有我个人的心得体会、优化思路及实战经验分享。无论是准备面试还是追求技术成长,我相信这些内容都能为您提供宝贵的参考与启发。期待您的光临,让我们共同在技术之路上不断前行!

相关文章:

归并延拓:LeetCode归并排序逆序对问题

前言 欢迎来到我的算法探索博客&#xff0c;在这里&#xff0c;我将通过解析精选的LeetCode题目&#xff0c;与您分享深刻的解题思路、多元化的解决方案以及宝贵的实战经验&#xff0c;旨在帮助每一位读者提升编程技能&#xff0c;领略算法之美。 &#x1f449;更多高频有趣Lee…...

51.WPF应用加图标指南 C#例子 WPF例子

完整步骤&#xff1a; 先使用文心一言生成一个图标如左边使用Windows图片编辑器编辑&#xff0c;去除背景使用正方形&#xff0c;放大图片使图标铺满图片使用格式工程转换为ico格式&#xff0c;分辨率为最大 在资源管理器中右键项目添加ico类型图片到项目里图片属性设置为始终…...

Springboot 注解缓存使用教程

Spring Boot Cache 注解使用教程 Spring Boot 提供了强大的缓存抽象,开发者可以通过注解快速实现缓存功能,从而提高系统性能。本教程将全面介绍 Spring Boot 提供的缓存相关注解及其作用,并结合示例讲解实际应用。 1. 常用缓存注解概览 Spring Boot 缓存提供以下核心注解…...

Python爬虫:从入门到实践

Python爬虫学习资料 Python爬虫学习资料 Python爬虫学习资料 在当今数字化信息爆炸的时代&#xff0c;数据已成为企业和个人发展的重要资产。Python爬虫作为一种高效获取网络数据的工具&#xff0c;正逐渐被广大开发者所熟知和应用。无论是市场调研、学术研究&#xff0c;还是…...

删除字符串中的所有相邻重复项(力扣1047)

这题也是属于栈的经典应用。为什么这样说呢&#xff1f;因为也是让我们删除相邻项。注意这里相邻项的理解&#xff0c;并不仅仅是说最开始的字符串相邻的项。在我们删除了某些相邻项后&#xff0c;会改变字符串&#xff0c;导致原本不相邻的字符变成相邻的&#xff0c;这同样属…...

MYSQL对数据的增删改查

DML 语句 对数据 进行 增、删、改 操作 插入 命令-- 插入值的个数 必须和 字段定义的个数相同 且 顺序 一致 insert into <tableName> values (val ...) ; /* 不推荐使用 */insert into <tableName>(col1 , col2 , ...) values(val1, val2 , ...) ;-- 批量插…...

前端——Html+CSS

目录 CSS引入方式 颜色表达方式 CSS选择器 去掉超链接的下划线 路径表示 行高和首行缩进 常见标签 布局标签 flex布局 表单标签 表单项标签 改变鼠标指针的样式 表格标签 div{ box-sizing: border-box; } CSS引入方式 具体有3种引入方式&#xff0c;语法如下表格所…...

Linux(DISK:raid5、LVM逻辑卷)

赛题拓扑: 题目: DISK 添加4块大小均为10G的虚拟磁盘,配置raid-5磁盘。创建LVM命名为/dev/vg01/lv01,大小为20G,格式化为ext4,挂在到本地目录/webdata,在分区内建立测试空文件disk.txt。[root@storagesrv ~]# yum install mdadm -y [root@storagesrv ~]# mdadm -C -n …...

N个utils(sql)

sql&#xff0c;操作数据库的语言&#xff0c;也可以叫做数据库软件的指令集吧。名字而已&#xff0c;无所谓啦。 本质上&#xff0c;sql并不是java语言内的范畴。但却是企业级开发的范畴。并且我整个文章的一篇逻辑的本质&#xff0c;层的概念&#xff0c;其中一个大的层级就…...

以太网实战AD采集上传上位机——FPGA学习笔记27

一、设计目标 使用FPGA实现AD模块驱动采集模拟电压&#xff0c;通过以太网上传到电脑上位机。 二、框架设计 数据位宽转换模块&#xff08;ad_10bit_to_16bit&#xff09;&#xff1a;为了方便数据传输&#xff0c;数据位宽转换模块实现了将十位的 AD 数据转换成十六位&#…...

Python数据分析案例70——基于神经网络的时间序列预测(滞后性的效果,预测中存在的问题)

背景 这篇文章可以说是基于 现代的一些神经网络的方法去做时间序列预测的一个介绍科普&#xff0c;也可以说是一个各种模型对比的案例&#xff0c;但也会谈一谈自己做了这么久关于神经网络的时间序列预测的论文&#xff0c;其中一些常见的模式及它们存在的问题以及效果&#x…...

vue+高德API搭建前端Echarts图表页面

利用vue搭建Echarts图表页面&#xff0c;在搭建Echarts图表中&#xff0c;如果搭建地理地形图需要准备一些额外的文件&#xff0c;地理json文件和js文件&#xff0c;js文件目前在网上只能找省一级的&#xff0c;json文件有对应的省市县&#xff0c;js文件和json文件对应的也是不…...

提示词工程:解锁AI潜能的关键技术

什么是提示词工程? 提示词工程(Prompt Engineering)是一门新兴的技术领域,专注于如何设计和优化与生成式人工智能的交互提示,以获得最佳的输出结果。它是连接人类意图和AI能力的桥梁,通过精心设计的文本输入来引导AI模型产生准确、相关且有价值的输出。 核心概念 提示(…...

Python制作简易PDF查看工具PDFViewerV1.0

PDFViewer PDF浏览工具&#xff0c;Python自制PDF查看工具&#xff0c;可实现基本翻页浏览功能&#xff0c;其它功能在进一步开发完善当中&#xff0c;如果有想一起开发的朋友&#xff0c;可以留言。本软件完全免费&#xff0c;自由使用。 软件界面简洁&#xff0c;有菜单栏、…...

嵌入式硬件篇---基本组合逻辑电路

文章目录 前言基本逻辑门电路1.与门&#xff08;AND Gate&#xff09;2.或门&#xff08;OR Gate&#xff09;3.非门&#xff08;NOT Gate&#xff09;4.与非门&#xff08;NAND Gate&#xff09;5.或非门&#xff08;NOR Gate&#xff09;6.异或门&#xff08;XOR Gate&#x…...

CSRF攻击XSS攻击

概述 ​在 HTML 中&#xff0c;<a>, <form>, <img>, <script>, <iframe>, <link> 等标签以及 Ajax 都可以指向一个资源地址&#xff0c;而所谓的跨域请求就是指&#xff1a;当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指…...

ARM学习(42)CortexM3/M4 MPU配置

笔者之前学习过CortexR5的MPU配置,现在学习一下CortexM3/M4 MPU配置 1、背景介绍 笔者在工作中遇到NXP MPU在访问异常地址时,就会出现总线挂死,所以需要MPU抓住异常,就需要配置MPU。具体背景情况可以参考ARM学习(41)NXP MCU总线挂死,CPU could not be halted以及无法连…...

opencv3.4 ffmpeg3.4 arm-linux 交叉编译

一些依赖安装&#xff1a; sudo apt-get install pkg-config libgtk2.0-dev libavcodec-dev libavformat-dev libswscale-dev 交叉编译工具链准备&#xff1a;gcc-linaro-6.3.1 1、下载 https://github.com/FFmpeg/FFmpeg 解压后新建目录&#xff1a;Fmpeg-n3.4.13/ffmpeg…...

spring的事物管理的认知

事物 它是一个原子操作要么全部不执行&#xff0c;要么全部执行成功&#xff0c;如果有一个失败也会撤销&#xff0c;它保证用户每一次的操作都是可靠的&#xff0c;即使时出现了错误也不至于破坏数据的完整性 它包含了四种特性&#xff1a; 原子性&#xff1a;保证事物要么…...

麒麟LINUX V10SP3 2401安装ORACLE 12.2.1 runInstaller直接报UNZIP格式不对

好久没有安装ORACLE了&#xff0c;一般都是RHEL上安装得比较多&#xff0c;这不&#xff0c;现在大家都是选择国产操作系统来安装数据库了&#xff0c;以前在龙蜥&#xff0c;欧拉&#xff0c;麒麟上也安装过&#xff0c;都没有问题&#xff0c;想来在麒麟LINUX v10sp3 2401上面…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...