图解:求逆序对数量(归并排序的应用)

简介: 图解:求逆序对数量(归并排序的应用)

前言:

本篇讲归并排序的应用——求解无序序列中逆序对的数目。如果需要了解归并排序本身,请跳转至我的另一篇文章归并排序图文详解(一篇讲透归并排序)-CSDN博客

题目

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

输入格式

第一行包含整数 n,表示数列的长度。

第二行包含 n 个整数,表示整个数列。

输出格式

输出一个整数,表示逆序对的个数。

数据范围

1≤n≤100000

数列中的元素的取值范围 [1,109][1,109]。

输入样例:
6
2 3 4 5 6 1
输出样例:
5

题目分析:

1、理解逆序对的含义:对于数组中的两个数,如果下标小的数的数值却大,那么这两个数就是一组逆序对。

2、本题的要求很简单,没有其他可以分析的。我们看到题目第一眼想到的肯定是暴力解法:就是先选择第一个数,然后一一比较后面的数,如果满足逆序对要求则+1.然后选择第二个数再和后面数一一比较,如此反复。这样写的话时间复杂度会在O(n^2)。当数据量一大后运行时间会非常可怕,所以本题肯定要考虑其他的解法。

解法分析:

归并排序思想:

1、回顾一下分离奇偶数的题目,就是给一个无序序列要求实现调整后,序列左边为奇数右边为偶数。本题我们采用的办法就是双指针,一个从左边向右走,一个从右边向左走,如果左指针遇到偶数则停止,右指针遇到奇数则停止。然后两者交换,接下来继续走直到两者相遇。这样子在运行中时刻会保持左指针左边为奇数,右指针右边为偶数的条件。

这个算法的思想和我们快速排序的核心思想是一样的。

这就说明快排和归并的核心思想很多时候能用在其他的算法当中。

2、那么归并的核心思想是什么呢?核心思想就是:采用的是双指针归并法(链表合并本质也是这样)(两两比较并合并)。我们想想这个思路能不能用在这里。

本题深入分析:

1、先上张图:

假如我们将整个数组分为两段。那么根据这两段我们可以将逆序对分为以上三种类型,然后一一进行求解再把每种的个数相加。

逆序对1:两个数全在左边(如图中红色点)

逆序对2:两个数全在右边(如图中绿色点)

逆序对3:一个数在左边区域,另一个数在右边区域(如图中黄色的点)

2、这时再假如逆序对3,这种类似的逆序对数目能够被计算出来。那么对于左边的逆序对1和右边的逆序对2,我们就可以通过递归的方式,将左边、右边再各自划分为两个区域,计算这新的区域中的逆序对3。

3、不停分割计算逆序对3,对于1、2的计算就是通过分割花为逆序对3,以及新的逆序对1、2.直到最后一组逆序对1、2只剩一个元素,则可以知道结果,并且过程中的逆序对3一直可以计算,所以到这里问题就可以化为求解逆序对3,这一个问题。

4、求解逆序对3:让我们想想归并排序的核心思想:合并的方法采用的是双指针归并法(链表合并本质也是这样)(两两比较并合并)。

那么对于本题能不能拿来用呢?假如我们两个有序数组,我们要如何求出逆序对数?下面我通过图来说明:

选择归并原因:

1、看到这里,大家肯定能想到,这双指针,然后一个个比较大小,然后让小的那个后移的操作和归并排序一模一样啊!!所以很自然,我们可以把这两个操作合并在一起。

2、同时,我们的操作的前提正好也是两个数组内部有序。而归并排序正好也满足合并过程中内部有序的条件。

代码分析:

#include<iostream>
using namespace std;
int temp[100001]={0};//这个temp对于每个递归来说必须是一样的。所以在函数外面定义
long ct_inver_merge(int num[],int l,int r){
    if(l>=r) return 0;
    int mid=(l+r)>>1;
    long result=0;
    result=ct_inver_merge(num,l,mid)+ct_inver_merge(num,mid+1,r);
//先求解左边和右边的两个子区间的逆序对数目
    int i=l;
    int j=mid+1;
    int k=0;//这个k对于每个递归来说都从0开始,所以必须在函数内定义
    while(i<=mid&&j<=r){
        if(num[i]<=num[j])temp[k++]=num[i++];
        else{
            temp[k++]=num[j++];
            result+=mid-i+1;
        }
//实现排序的同时计算两个有序数组间逆序对3的数目,并加到前面的result中
    }
    while(i<=mid)temp[k++]=num[i++];
    while(j<=r)temp[k++]=num[j++];
//单纯为了实现归并排序
    for(int i=l,j=0;i<=r;i++,j++){
        num[i]=temp[j];
    }
//归并排序的必要操作。求逆序对3的算法基于就是数组内部有序。
//所以实现归并保持内部有序是必须的
    return result;
}
int main(){
    int n=0;
    int num[100001]={0};
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>num[i];
    }
    cout<<ct_inver_merge(num,0,n-1)<<endl;
}

 

相关文章
|
人工智能 弹性计算 关系型数据库
OCP China Day 2022:vODLA异构计算资源池化技术架构和实践
OCP会议信息8月10日,由OCP社区主办、浪潮信息承办的OCP China Day 2022(开发计算中国技术峰会)在北京举行。开放计算正式成为当前及至未来数据中心的创新主力,通过全球化协作的创新模式,解决数据中心基础设施可持续发展的重大问题。OCP China Day作为开放计算领域生态覆盖最广且最具影响力的亚洲最大年度技术峰会,迄今已经成功举办4届。本届峰会以“开放.向未来:绿色、融合、赋能
OCP China Day 2022:vODLA异构计算资源池化技术架构和实践
|
数据采集 算法 机器人
软件体系结构 - 调度算法(3) 单调速率调度算法
【4月更文挑战第19天】软件体系结构 - 调度算法(3) 单调速率调度算法
422 0
|
安全 Java 编译器
kotlin面试题
kotlin面试题
871 1
|
SQL 大数据 关系型数据库
开源大数据比对平台(dataCompare)新版本发布
开源大数据比对平台(dataCompare)新版本发布
902 0
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
存储 编解码 文件存储
Windows 中的硬链接、目录联接(软链接)、符号链接、快捷方式
【10月更文挑战第5天】本文介绍了四种链接类型的概念及用途:硬链接允许通过多个入口访问同一文件内容,适用于不复制文件的情况下提供多处访问;软链接(目录联接)用于创建目录间的虚拟映射,可跨越文件系统;符号链接则更为灵活,可链接文件或目录并指向任意路径;快捷方式则是Windows中常用的一种特殊文件类型,便于快速访问程序、文件或网络资源。分别描述了它们的定义、工作原理、特点以及创建方法。
3337 10
|
IDE Java 项目管理
【Maven】Maven的新建、使用、安装配置、集成配置到eclipse,Maven项目测试servlet,Maven容易出现的问题
Maven是一个流行的构建工具和项目管理工具,它能够自动处理项目的编译、依赖管理和构建部署等任务。通过使用Maven,开发人员可以更轻松地管理和构建Java项目,而不必手动解决复杂的依赖关系。Maven是一个Java项目管理工具,它提供了一种结构化的方法来管理项目的构建、依赖、文档和发布等方面的工作。它基于项目对象模型(Project Object Model,POM)的概念,通过配置文件来定义项目的构建和行为。Maven将项目的构建过程自动化,并提供了许多插件和功能来简化开发人员的工作。
|
机器学习/深度学习 人工智能 自然语言处理
【深度学习】python之人工智能应用篇--跨模态生成技术
跨模态生成技术是一种将不同模态的数据(如文本、图像、音频、视频等)进行融合和转换的技术。其目标是通过将一个模态的数据作为输入,生成与之对应的另一个模态的输出。这种技术对于突破单一模态的局限性,提高信息处理的准确性和丰富性具有重要意义。跨模态生成技术主要依赖于深度学习和生成模型,通过学习和模拟不同模态之间的映射关系来实现模态间的转换。
544 1
|
小程序 安全 搜索推荐
【微信小程序开发实战项目】——个人中心页面的制作
本文介绍了如何设计和实现一个网上花店的微信小程序,包括个人中心、我的订单和我的地址等功能模块。个人中心让用户能够查看订单历史、管理地址和与客服互动。代码示例展示了`own.wxml`、`own.wxss`和`own.js`文件,用于构建个人中心界面,包括用户信息、订单链接、收藏、地址、客服和版本信息。我的订单部分展示了订单详情,包括商品图片、名称、销量、价格和订单状态,用户可以查看和管理订单。我的地址功能允许用户输入和编辑收货信息,包括联系人、性别、电话、城市和详细地址。每个功能模块都附有相应的WXML和WXSS代码,以及简洁的样式设计。
898 0
【微信小程序开发实战项目】——个人中心页面的制作
|
存储 数据库 对象存储
IOS的四种数据存储方式及优劣
IOS的四种数据存储方式及优劣
487 1

热门文章

最新文章