算法的学习笔记—数组中的逆序对(牛客JZ51)


😀前言
在算法和数据结构领域,"逆序对"是一个经典问题。它在数组中两个数字之间定义,若前面的数字大于后面的数字,则这两个数字组成一个逆序对。我们要做的就是,给定一个数组,找出数组中所有的逆序对并计算其总数。
🏠个人主页:尘觉主页
文章目录
- 🥰数组中的逆序对
- 😄问题描述
- 示例
- 😃解题思路
- 归并排序思想
- 具体步骤
- 💖代码实现
- 代码讲解
- 时间复杂度分析
- 😄总结
🥰数组中的逆序对
NowCoder
😄问题描述
给定一个数组,数组中的两个数字如果满足以下条件,则它们组成一个逆序对:
- 假设数组为
nums[i]和nums[j],若i < j并且nums[i] > nums[j],则(nums[i], nums[j])是一个逆序对。
目标是计算数组中这样的逆序对的数量。
示例
假设给定的数组为 [7, 5, 6, 4]。通过观察可以得到以下逆序对:
(7, 5)(7, 6)(7, 4)(5, 4)(6, 4)
总共有 5 对逆序对,因此最终结果为 5。
😃解题思路
直接使用双重循环暴力枚举每一对元素来检查是否为逆序对的复杂度为 O ( n 2 ) O(n^2) O(n2),这在数组规模较大时效率较低。为了解决这个问题,我们可以借助归并排序算法,通过将问题分解为更小的子问题来提高效率。
归并排序思想
归并排序是一种分治算法。它将一个大的问题分解为两个小的子问题,递归地解决子问题,最后将子问题的解合并成原问题的解。在计算逆序对时,我们可以通过在归并的过程中统计逆序对的数量,从而实现线性对数级别的时间复杂度 O ( n log n ) O(n \log n) O(nlogn)。
具体步骤
- 分解问题: 将数组分成左右两部分,分别对左右部分进行归并排序。
- 归并: 在归并的过程中,若左半部分的某个数字大于右半部分的某个数字,那么这个数字及左半部分后续的所有数字都比右半部分的数字大,形成逆序对。我们可以在归并的过程中统计这些逆序对。
💖代码实现
以下是基于归并排序来解决逆序对问题的Java代码实现:
private long cnt = 0; // 用于计数逆序对的数量
private int[] tmp; // 辅助数组,避免在递归过程中多次创建新数组public int InversePairs(int[] nums) {tmp = new int[nums.length];mergeSort(nums, 0, nums.length - 1);return (int) (cnt % 1000000007); // 结果对1000000007取模,防止结果过大
}private void mergeSort(int[] nums, int l, int h) {if (h - l < 1) // 当子数组的长度小于等于1时,不需要进行排序return;int m = l + (h - l) / 2; // 计算中间位置mergeSort(nums, l, m); // 递归排序左半部分mergeSort(nums, m + 1, h); // 递归排序右半部分merge(nums, l, m, h); // 合并排序后的两个子数组
}private void merge(int[] nums, int l, int m, int h) {int i = l, j = m + 1, k = l; // 初始化左右指针和辅助数组的指针while (i <= m || j <= h) { // 当左、右两部分数组未完全处理完时if (i > m) {tmp[k] = nums[j++]; // 左边处理完了,直接将右边的元素加入辅助数组} else if (j > h) {tmp[k] = nums[i++]; // 右边处理完了,直接将左边的元素加入辅助数组} else if (nums[i] <= nums[j]) {tmp[k] = nums[i++]; // 左边元素小于等于右边元素,加入辅助数组} else {tmp[k] = nums[j++]; // 右边元素小于左边元素,加入辅助数组cnt += m - i + 1; // 统计逆序对,左边的剩余元素都比当前右边元素大}k++;}// 将辅助数组的结果复制回原数组for (k = l; k <= h; k++)nums[k] = tmp[k];
}
代码讲解
cnt:用于计数逆序对的总数量。tmp:辅助数组,用于在归并时暂存排序后的子数组。InversePairs方法:对输入数组调用归并排序,并返回逆序对数量。为了避免结果过大,返回时对 1000000007 取模。mergeSort方法:实现归并排序的递归逻辑,将数组分为两部分,分别进行排序,并在排序过程中调用merge方法。merge方法:实现两个已排序子数组的合并过程,同时统计逆序对的数量。若左边子数组的某个元素大于右边子数组的当前元素,则说明该元素与右边子数组当前元素及其后的所有元素都形成了逆序对。
时间复杂度分析
归并排序的时间复杂度是 O ( n log n ) O(n \log n) O(nlogn),其中 n n n 是数组的长度。由于在归并的过程中我们只需额外进行 O ( n ) O(n) O(n) 的操作来统计逆序对,因此整个算法的时间复杂度仍然是 O ( n log n ) O(n \log n) O(nlogn)。这比直接使用 O ( n 2 ) O(n^2) O(n2) 的双重循环要高效得多,特别是在数组规模较大时。
😄总结
逆序对问题是一个经典的算法问题,借助归并排序可以将其优化至 O ( n log n ) O(n \log n) O(nlogn) 的时间复杂度。通过在归并排序的过程中适时地统计逆序对,我们可以有效地解决这个问题。
😁热门专栏推荐
想学习vue的可以看看这个
java基础合集
数据库合集
redis合集
nginx合集
linux合集
手写机制
微服务组件
spring_尘觉
springMVC
mybits
等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持
🤔欢迎大家加入我的社区 尘觉社区
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞

相关文章:
算法的学习笔记—数组中的逆序对(牛客JZ51)
😀前言 在算法和数据结构领域,"逆序对"是一个经典问题。它在数组中两个数字之间定义,若前面的数字大于后面的数字,则这两个数字组成一个逆序对。我们要做的就是,给定一个数组,找出数组中所有的逆…...
Golang | Leetcode Golang题解之第498题对角线遍历
题目: 题解: func findDiagonalOrder(mat [][]int) []int {m, n : len(mat), len(mat[0])ans : make([]int, 0, m*n)for i : 0; i < mn-1; i {if i%2 1 {x : max(i-n1, 0)y : min(i, n-1)for x < m && y > 0 {ans append(ans, mat[x…...
什么是全局污染?怎么避免全局污染?
全局污染(Global Pollution)是指在编程过程中,过度使用全局变量或对象导致命名冲突、代码可维护性下降及潜在错误增加的问题。在 JavaScript 等动态语言中,尤其需要关注全局污染的风险。 全局污染的影响 1. 命名冲突 3. 意外修改…...
C# 串口通信教程
串口通信(Serial Communication)是一种用于设备之间数据传输的常见方法,通常用于与外部硬件设备(如传感器、机器人、微控制器)进行通信。在 C# 中,System.IO.Ports 命名空间提供了与串口设备交互的功能&…...
PHP编程基础
PHP(Hypertext Preprocessor,超文本预处理器)是一种广泛使用的开源服务器端脚本语言,主要用于网页开发,同时也可以进行命令行脚本编写。以下是PHP编程的基础知识: 1. PHP文件结构 PHP文件通常以 .php 为扩…...
TwinCAT3下位机配置EAP通讯传递与接收变量
添加EAP设备 DEVICE中右键选择添加新项,添加EAP(EtherCAT Automation Protocal)选择Network Variables类型,如下图。 设置网络适配器来激活EAP,在Adapter中选择search,选择网络适配器后确定,…...
近似推断 - 期望最大化(EM)篇
前言 近似推断是统计学和机器学习中一个至关重要的领域,尤其在处理复杂模型和不完全数据时显得尤为重要。期望最大化( Expectation Maximization \text{Expectation Maximization} Expectation Maximization,简称 EM \text{EM} EM࿰…...
arp欺骗及其实验
ARP欺骗(ARP Spoofing)是一种网络攻击技术,攻击者通过伪造ARP(地址解析协议)消息,将其MAC地址与目标IP地址关联,从而实现对网络流量的截获、篡改或重定向。以下是ARP欺骗的详细信息:…...
HDU The Boss on Mars(容斥原理)
题目大意: ACM 有 n 名员工,现在是他们从老板那里拿薪水的时候了。所有员工都从 1 到 n 编号。原因不明,如果员工的工作编号是 k,他今年可以获得 k^4 Mars 美元。所以为 ACM 工作的员工非常富有。 因为员工人数太多,…...
nnUnet 大模型学习笔记(续):训练网络(3d_fullres)以及数据集标签的处理
目录 1. 数据集处理 1.1 实现脚本 1.2 json文件 2. 设置读取路径 2.1 设置路径 2.2 数据集转换 2.3 数据集预处理 2.4 训练(3d_fullres) 3. 训练结果展示 关于nnUnet 数据集的处理和环境搭建,参考上文:第四章:nnUnet大模…...
Java中的数据结构与集合源码
目录 一、数据结构 1.1 数据结构概念 1.2 研究对象 1.3 常见存储结构 1.3.1 数组 1.3.2 链表 1.单向链表 2.双向链表 1.3.3 二叉树 1.3.4 栈(FILO,先进后出) 1.3.5 队列(FIFO,先进先出) 二、集合…...
Java应用程序的测试覆盖率之设计与实现(三)-- jacoco cli 客户端
一、背景 上文已把覆盖率数据采集好了,并提供远程连接的tcp地址及端口。 jacoco cli文档jacoco cli jar包 jacococli.jar 我下载好了,放在github工程里。 本文主要是介绍如何使用jacoco cli 客户端读取并生成覆盖率报告。 二、使用 1、dump覆盖率统…...
Deepin V23 / 统信UOS 下安装与配置 tftp
几个月前,我将开发系统从 ubuntu 切换到 Deepin,当时写过一篇文章《使用国产操作系统作为开发系统》。几个月下来,没有感觉有什么不适应,Ubuntu 能做的事情,在 Deepin 上都能做。而且有 UOS 应用商店的加持,…...
java基础学习:定时任务常见实现方式
一、Timer解析 TaskQueue:小顶堆,存放timeTask。 TimerThread:任务执行线程 死循环不断检查是否有任务需要开始执行,有就执行它。始终是一个线程在执行。 单线程执行任务,任务有可能相互阻塞: schedul…...
句柄是什么?有什么用?举例说明
在C#编程中,“句柄”(Handle)是一个与操作系统资源相关联的标识符。句柄是一个指针或者索引,用于在程序代码中引用系统资源,如窗口、文件、线程等。由于直接操作这些资源非常危险且复杂,操作系统提供句柄作…...
Jenkins学习笔记
Jenkins学习笔记 NumTitleComments1官网 官方网站 中文文档2基础Jenkins基础3groovy1.groovy语法 2.groovy 入门4pipelinepipeline基本语法介绍5Github actiongithub action6Shared library1 2...
AI 解读软考高级操作系统顺序存取、直接存取、随机存取、相联存取的区别
这几个术语描述了不同类型的存储方式,它们涉及数据存取的顺序和灵活性。为了更好地理解,我们可以先通过生活中的例子来感受这些概念。 生活化例子 1. 顺序存取: 想象你在看一盘录像带(比如老式的VHS录像带)。如果你想…...
STM32烧写准备
目录 一.安装stlink驱动二.烧写器固件升级三.安装烧写程序四.进行测试1.流水灯 五.出现的问题1.升级固件问题2.测试时连接问题 一.安装stlink驱动 amd64是用在64位的,x86用在32位;双击运行即可 出现以下情况表示安装完成当连接上STM32开发板时ÿ…...
为Windows Terminal 配置zsh + Oh-My-Zsh!
参考: 为Windows Terminal 配置zsh Oh-My-Zsh! [非WSL] https://zhuanlan.zhihu.com/p/625583037 Package: zsh - MSYS2 Packages 安装配置 1、安装 Windows Terminal(必须) Method 1: 打开 Microsoft Store,搜索 “Windows Terminal”。点击 “…...
RNN、LSTM 与 Bi-LSTM
一. RNN 循环神经网络(Recurrent Neural Network, RNN)是深度学习领域一类具有内部自连接的神经网络能够学习复杂的矢量到矢量的映射。 最大特点:前面的序列数据可以用作后面的结果预测中。 一个简单的循环神经网络结构,其结构包…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
