算法进阶——数组中的逆序对

news/2024/12/2 12:58:37/

题目


在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007

数据范围:对于 50% 的数据, size≤104
对于 100% 的数据, size≤105
数组中所有数字的值满足 0≤val≤109

要求:空间复杂度O(n),时间复杂度O(nlogn)

输入描述:
题目保证输入的数组中没有的相同的数字

示例1

输入:
[1,2,3,4,5,6,7,0]
返回值:
7

示例2

输入:
[1,2,3]
返回值:
0

思路


这题可以用归并统计法,也就是在归并排序的同时进行统计。

先了解归并排序算法,主要思想是先分后并:

  • 将数组分为两个子数组,两个子数组分为四个子数组,依次向下分,直到数组不能再分为止。
  • 从最小的数组按照顺序合并,从小到大或从大到小,依次向上合并,最后得到合并完的顺序数组。

归并统计法,关键点在于合并环节,在合并数组的时候,当发现右边的小于左边的时候,此时可以直接求出当前产生的逆序对的个数。

举个例子:
在合并 {4 ,5} {1 , 2} 的时候,首先我们判断 1 < 4,我们即可统计出逆序对为2,为什么呢?这利用了数组的部分有序性。因为我们知道 {4 ,5} 这个数组必然是有序的,因为是合并上来的。此时当 1比4小的时候,证明4以后的数也都比1大,此时就构成了从4开始到 {4,5}这个数组结束,这么多个逆序对(2个),此时利用一个临时数组,将1存放起来,接着比较2和4的大小,同样可以得到有2个逆序对,于是将2也放进临时数组中,此时右边数组已经完全没有元素了,则将左边剩余的元素全部放进临时元素中,最后将临时数组中的元素放进原数组对应的位置。

可以看到下面这张图:

解答代码


class Solution {
public:/*** @param nums int整型vector * @return int整型*/int InversePairs(vector<int>& nums) {// write code hereint res = 0;vector<int> tmp(nums.size());MergeSort(nums, tmp, 0, nums.size() - 1, res);return res;}void MergeSort(vector<int>& nums, vector<int>& tmp, int left, int right, int& res) {// 递归结束if (left >= right) {return;}// 中心点int mid = left + (right - left) / 2;// 归并MergeSort(nums, tmp, left, mid, res);MergeSort(nums, tmp, mid + 1, right, res);Merge(nums, tmp, left, mid, right, res);}void Merge(vector<int>& nums, vector<int>& tmp, int left, int mid, int right, int& res) {int i = left; // 左子数组下标起点int j = mid + 1; // 右子数组下标起点int k = 0; //临时数组的下标起点while (i <= mid && j <= right) {if (nums[i] < nums[j]) {// 左子数组元素当前元素较小,无逆序,只进行排序tmp[k++] = nums[i++];} else {// 左子数组元素当前元素较大,排序同时记录逆序数tmp[k++] = nums[j++];res += mid + 1 - i;res %= 1000000007; // 应题目要求}}// 子数组中剩下元素全部存入临时数组while (i <= mid) {tmp[k++] = nums[i++];}while (j <= right) {tmp[k++] = nums[j++];}// 完成排序for (int i = left, j = 0; i <= right; i++, j++) {nums[i] = tmp[j];}}
};

http://www.ppmy.cn/news/1174160.html

相关文章

golang获取操作系统信息:CPU,内存,网络,磁盘,进程管理,传感器(温度,风扇,电池)

扩展包&#xff1a;github.com/shirou/gopsutil&#xff0c;此项目是在https://github.com/giampaolo/psutil的基础上&#xff0c;基于golang的实现。 go get github.com/shirou/gopsutil/v3 package mainimport ("fmt""github.com/shirou/gopsutil/v3/mem&qu…

SpringBoot整合Activiti7——任务监听器(七)

文章目录 一、任务监听器事件类型配置方式(选)代码实现xml文件创建监听器class方式expression方式delegateExpression 测试流程部署流程启动流程完成任务 一、任务监听器 任务监听器可以在任务创建、任务分配、任务完成、任务删除发生时触发&#xff0c;从而执行相应的逻辑。 事…

交换机基础(四):MSTP负载均衡配置案例

如图所示是某个企业内部核心网络的结构图&#xff0c;目前企业中有20个VLAN, 编号为VLAN1&#xff5e;VLAN20, 为了确保内部网络的可靠性&#xff0c;使用 了冗余链路和MSTP 协议。为了能更好地利用网络资源和带宽&#xff0c;现管理员希望通过配置MSTP 的负载均衡实现网络带宽…

1024程序员节

一年一年真快啊&#xff0c;

【proteus】8086 写一个汇编程序并调试

参考书籍&#xff1a;微机原理与接口技术——基于8086和Proteus仿真&#xff08;第3版&#xff09;p103-105&#xff0c;p119-122. 参考程序是p70&#xff0c;例4-1 在上一篇的基础上&#xff1a; 创建项目和汇编文件 写一个汇编程序并编译 双击8086的元件图&#xff1a; …

我想要一个勋章

目录 一、背景二、过程三、总结 一、背景 十年前结缘&#xff0c;也许是冥冥中自有天注定&#xff0c;注定要给自己多加一个今天的节日。 二、过程 一个勋章&#xff0c;一个有意义的标志。 一个勋章&#xff0c;一个时间轮上的帧。 一个勋章&#xff0c;一个二进制的节点。…

腾讯云阿里云服务器mongdb数据库设置密码

避坑点 数据库绑定ip一定要设置0.0.0.0 设置超级管理员账号密码 1、可以使用navicat15连接mongodb数据库&#xff0c;进入命令行界面&#xff0c;输入以下命令 如出现找不到MongoDB shell为可执行文件&#xff0c;选择设置路径&#xff0c;路径为&#xff1a;MongoDB shell是…

最小二乘法,可视化UI界面

import tkinter as tk import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from pylab import mplmpl.rcParams[font.sans-serif] [FangSong] # 指定默认字体 mpl.rcParams[axes.unicode_minus] False …