【Leetcode每日一题】 分治 - 交易逆序对的总数(难度⭐⭐⭐)(74)

ops/2025/2/7 12:34:51/

1. 题目解析

题目链接:LCR 170. 交易逆序对的总数

这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。

2.算法原理

归并排序的基本思路

归并排序将数组从中间分成两部分,在排序的过程中,逆序对的来源分为以下三类:

  1. 左子数组内部的逆序对
  2. 右子数组内部的逆序对
  3. 跨越左右子数组的逆序对

最终的逆序对总数是这三类逆序对的总和。归并排序的整体步骤如下:

  1. 排序左子数组
  2. 排序右子数组
  3. 合并两个有序子数组
利用归并排序统计逆序数的原理

在归并排序的合并过程中,左、右子数组始终保持有序状态。我们可以利用这一特性快速统计跨越左右子数组的逆序对数量,而不必遍历所有可能的组合。

具体计算逆序数的方法

合并两个有序数组时,可以通过以下两种方式之一统计逆序数:

  1. 统计某个数之前的有多少个数比它大
  2. 统计某个数之后的有多少个数比它小

我们重点分析第一种方式的原理。

示例分析

假设两个有序数组和辅助数组为 left = [5, 7, 9]right = [4, 5, 8]help = []。通过合并的过程可以求得逆序数。定义如下变量:

  • cur1:遍历 left 数组的指针
  • cur2:遍历 right 数组的指针
  • ret:记录逆序数的计数器

合并的具体步骤如下:

  1. 第一轮left[cur1] > right[cur2]。因为 left 数组中 [cur1, 2] 区间的所有元素均大于 right[cur2],这些元素可以与 right[cur2] 构成逆序对。因此,更新 ret += 3 并将 right[cur2] 放入 help 数组,同时 cur2++

  2. 第二轮left[cur1] == right[cur2]。此时 right[cur2] 可能与 left 中的其他元素形成逆序对,因此将 left[cur1] 放入 help 数组。没有新增逆序对,不更新 ret

  3. 第三轮left[cur1] > right[cur2]。与第一轮类似,left[cur1, 2] 区间内的元素均大于 right[cur2],更新 ret += 2,并将 right[cur2] 放入 help 数组,cur2++

  4. 第四轮left[cur1] < right[cur2]left[cur1]right 中的所有元素小,不构成逆序对。直接将 left[cur1] 放入 help 数组,不更新 ret

  5. 第五轮left[cur1] > right[cur2]。此时 left 中的元素能与 right[cur2] 构成逆序对,更新 ret += 1,并将 right[cur2] 放入 help 数组。

处理剩余元素

在合并过程中,如果 left 中还有剩余元素,说明这些元素已经与 right 中的元素计算过,不会新增逆序对。直接将剩余元素放入 help 数组。如果 right 中还有剩余元素,则这些元素均比 left 中的元素大,同样不会构成逆序对。

小结

通过上述方式利用归并排序的合并过程,可以快速统计逆序数。复杂度为 O(N log N),相较于暴力解法的 O(N^2) 效率更高。

3.代码编写

class Solution {int tmp[50010];public:int reversePairs(vector<int>& nums) {return mergeSort(nums, 0, nums.size() - 1);}int mergeSort(vector<int>& nums, int left, int right) {if (left >= right)return 0;int ret = 0;// 1. 找中间点,将数组分成两部分int mid = (left + right) >> 1;// [left, mid][mid + 1, right]// 2. 左边的个数 + 排序 + 右边的个数 + 排序ret += mergeSort(nums, left, mid);ret += mergeSort(nums, mid + 1, right);// 3. ⼀左⼀右的个数int cur1 = left, cur2 = mid + 1, i = 0;while (cur1 <= mid && cur2 <= right) // 升序的时候{if (nums[cur1] <= nums[cur2]) {tmp[i++] = nums[cur1++];} else {ret += mid - cur1 + 1;tmp[i++] = nums[cur2++];}}// 4. 处理⼀下排序while (cur1 <= mid)tmp[i++] = nums[cur1++];while (cur2 <= right)tmp[i++] = nums[cur2++];for (int j = left; j <= right; j++)nums[j] = tmp[j - left];return ret;}
};

The Last

嗯,就是这样啦,文章到这里就结束啦,真心感谢你花时间来读。

觉得有点收获的话,不妨给我点个吧!

如果发现文章有啥漏洞或错误的地方,欢迎私信我或者在评论里提醒一声~


http://www.ppmy.cn/ops/38681.html

相关文章

片冰机工作原理

片冰机工作原理 1、制冰用的水需要加盐(行话叫做加药)至于多少量。看制冰量多少调制泵(柱塞泵)自动调整。 2、制冰机主体分两腔体外腔体内盘的一定密度的铜管。专业术语叫(蒸发腔)就是俗话讲的制冷的东西。 3、外腔体内是一个很规则的圆不锈钢腔体&#xff0c;中心有一三叶刮…

ESP32引脚入门指南(三):从理论到实践(Touch Pin)

引言 ESP32作为物联网领域的明星微控制器&#xff0c;不仅以其强大的网络通信能力著称&#xff0c;还内置了丰富的外设资源&#xff0c;其中就包括电容式触摸传感&#xff08;Capacitive Touch&#xff09;功能。本文旨在深入浅出地介绍ESP32的Touch引脚&#xff0c;带你了解其…

论文笔记:DeepMove: Predicting Human Mobility with Attentional Recurrent Networks

WWW 2018 1 Intro 根据对百万级用户群的研究&#xff0c;93%的人类移动是可预测的。 早期的mobility预测方法大多基于模式的。 首先从轨迹中发现预定义的移动模式(顺序模式、周期模式)然后基于这些提取的模式预测未来位置。最近的发展转向基于模型的方法进行流动性预测。 利用…

Android app通过jcifs-ng实现Samba连接共享文件夹

Android端使用Samba连接共享文件夹&#xff0c;下载或上传文件的功能实现。如果你是用jcifs工具包&#xff0c;那么你要注意jcifs-ng 和 jcifs 支持的SMB版本区别。 JCIFS-NG的github地址 JCIFS官网地址 这里有关于jciffs、jcifs-codelibs、jcifs-ng、smbj的详细介绍 对比 支…

自然语言(NLP)

It’s time for us to learn how to analyse natural language documents, using Natural Language Processing (NLP). We’ll be focusing on the Hugging Face ecosystem, especially the Transformers library, and the vast collection of pretrained NLP models. Our proj…

Coze扣子开发指南:用免费API自己创建插件

虽然Coze扣子现在插件商店已经有几百个插件了&#xff0c;但相对于海量人群的众多差异化需求&#xff0c;还是远远不够的。如果插件商店没有合适的插件&#xff0c;其实完成可以自己创建&#xff0c;过程也很简单&#xff0c;不需要编写任何代码。 首先打开个人空间&#xff0…

计算机网络 第三章 数据链路层 数据链路层的三大问题

一、数据链路层前导知识 1.1 整体了解数据在网络传输的整体过程 计算机网络分为五个层次&#xff0c;从下往上依次是物理层&#xff08;实际传输01代码&#xff09;&#xff0c;数据链路层&#xff0c;网络层&#xff0c;运输层&#xff0c;应用层。这一次我们学习的是数据链…

初学者理解Transformer,本文is all you need

要问现在AI领域哪个概念最热&#xff0c;必然是openAI推出chatGPT之后引发的大模型。然而这项技术的起源&#xff0c;都来自一篇google公司员工的神作“Attention Is All You Need”——本文标题也是一种致敬^_^&#xff0c;目前已有近12万的引用(还在增长)。 在“Attention Is…