在逆序对的问题中,如果采用暴力求解的方法,一般也是有效的,但是O(n2)时间复杂度实在是难以接受的。但是对于逆序对问题,却有一个看似不想关的算法来解决–归并排序。时间复杂度和空间复杂度完全与归并排序一样,只是在归并过程中,添加了一个变量,对于逆序对的数目进行了记录。这样就将时间复杂度降低到了O(nlogn)。

原理

因为逆序对的数目可能存在平方数个逆序对,因此要想将逆序对数目求解的复杂度降低到O(nlogn),就不能对每一个逆序对进行计算。根据归并排序思想,使用归并求解逆序对时,将会在将两个有序数组合并成一个有序数组的过程中,记录逆序对的数目,其他如数组划分和排序过程同归并排序。

在归并排序的合并步骤中,假设将两个有序数组A[] 和有序数组B[] 和并为一个有序数组C[]。计算逆序对问题转换为计算逆序对(a,b)的问题,其中a来自A[], b来自B[]。当a < b的时候,不计数,当a>b的时候(a,b)就是逆序对,由于A[]是有序的,那么A[]中位于a之后的元素对于B[]中的元素b也形成了逆序对,于是对于逆序对(a,b),(假设A[]的起始下标为sa,结束下标为ea,a的下标为pos)实际上合并成C[]后会会产生ea-pos+1个逆序对。

也就是说,合并过程中,每次出现一对这样的(a,b),逆序对数目sum = sum + ea-pos+1 ;
根据这样的原理,再给予对归并排序的理解,将上面的计算公式加入到归并排序中,就可以在O(nlogn)的时间复杂度里计算出一个给定数字序列中逆序对的数目。

示例代码

#include<iostream>#define N 100000using namespace std;void merge(int arr[],int start,int mid,int end,int temp[],long long *count){int index = 0,index1 = 0,index2 = 0;index = 0; index1 = start; index2 = mid+1;while((index1<=mid) && (index2<=end)){if(arr[index1] <= arr[index2]){temp[index++] = arr[index1++];}else{temp[index++] = arr[index2++];//ans+=e1-p1+1;(*count) = (*count) + mid - index1 + 1;}}while(index1<=mid)temp[index++] = arr[index1++];while(index2<=end)temp[index++] = arr[index2++];for(int i=0;i<index;i++){// 复制也是递归进行的,所以并不是从start开始到endarr[start+i] = temp[i];}}void mergeSort(int arr[],int start,int end,int temp[],long long *count){if(start<end){ // 递归出口int mid = 0;mid = (start+end)>>1;mergeSort(arr,start,mid,temp,count);mergeSort(arr,mid+1,end,temp,count);merge(arr,start,mid,end,temp,count);}}int main(){long long count = 0;int m = 0;cin>>m;int *a = new int[m];for(int i=0;i<m;i++){cin>>a[i];}int *temp = new int[m];mergeSort(a,0,m-1,temp,&count);delete []a;delete []temp;cout<<count<<endl;return 0;}

输入格式为:先输入一个数字代表数组的长度,回车,接下来依次输入以空格分割的n个数组元素。输出就是该数组的逆序对数目。

利用归并排序求逆序对相关推荐

  1. 信息竞赛进阶指南--归并排序求逆序对

    // 归并排序求逆序对 void merge(int l, int mid, int r) {// 合并a[l~mid]与a[mid+1~r]// a是待排序数组, b是临时数组, cnt是逆序对个数 ...

  2. 分治法:归并排序求逆序对

    现给出这个定义,什么是逆序对,NOIP火柴排队这个题是逆序对的一个比较好的例题,这里我们只讨论求逆序对的一些高效的算法 一般有归并排序以及树状数组两种方法,本文只讨论归并排序求逆序对 这里不给出原理只 ...

  3. hust1347(归并排序求逆序对)

    题意: 给出一个数列,你要对这个数列的数字进行k次交换操作,使得交换之后的数列逆序对虽少. 思路: 求原数列的逆序对,再和k比就行了.求逆序对要用归并排序,因为树状数组开不下. 代码: #includ ...

  4. 归并排序求逆序对(C语言)

    目录 1.归并排序过程 (1)逆序对概念 (2)基本思想 (3)算法实现 1.归并排序过程 使用归并排序实现求逆序对,那么首先得了解什么是归并排序(关于归并排序可以求逆序对,也是在做题中学会的). 首 ...

  5. -9 逆序输出一个整数的各位数字_【每日算法】基础算法——归并排序[求逆序对的数量](四)(思想很经典)...

    题目内容 给定一个长度为n的整数数列,请你计算数列中的逆序对的数量. 逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆 ...

  6. codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)

    题目链接: C. Mashmokh and Reverse Operation time limit per test 4 seconds memory limit per test 512 mega ...

  7. 归并排序——求逆序对个数

    求解逆序对个数 逆序对 对于一个包含N个非负整数的数组A[1-n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对. 例如,数组( ...

  8. 【NOI导刊】【归并排序求逆序对】最接近神的人

    题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着"神的殿堂".小FF猜 ...

  9. 逆序对算法c语言,归并排序求逆序对的代码(C语言)

    #include #include #define MAX 32767 int merge(int *array, int p,int q,int r) { //归并array[p...q] 与 ar ...

最新文章

  1. 准备把平台挪到linux
  2. matplotlib显示中文
  3. java:this和super
  4. OpenGL编程指南8:模型组合变换
  5. Python简单的抓取静态网页内容
  6. 读写XML文档时,去掉新增加节点的“空命名空间”(xmlns=””)
  7. python爬虫——批量爬取百度图片
  8. 搜索引擎选择: Elasticsearch与Solr(转载)
  9. 【无标题】免费公众号对接电影自动回复功能教程详解
  10. 个人定制ESXi安装程序(集成三方网卡驱动程序)
  11. 【Tool】常用 GIT 命令参阅
  12. Linux下打包压缩war和解压war包
  13. 复杂的1秒--图解Google搜索技术
  14. C语言规定 在一个源程序中 main函数,C语言规定:在一个源程序中,main函数的位置()A.必须在程序的最开始B.必须在系统调用的库函数的_搜题易...
  15. 音乐播放器 —— C++
  16. MobileNetv2-SSDlite训练自己的数据集(一)——配置安装caffe-ssd
  17. sublime Text 3 javaScript代码自动提示插件安装步骤
  18. [Share]17个免费下载电子书的网站
  19. 微医的第七年:依托互联网医院联合体,如何推动人工智能的战略升级?
  20. 发票扫一扫识别,一键导出表格

热门文章

  1. go语言 rlock() defer runlock()_Go并发编程之美-读写锁
  2. C++知识点41——运算符的重载概念与分数类实现(下)
  3. 边缘与锐化滤波(MATLAB)
  4. Php如何发出请求,PHP中如何发送HTTP请求?
  5. Oracle11G_逻辑备份
  6. 【C#】list 去重
  7. 使用Intellij IEDA创建hibernate
  8. ZeroClipboard跨浏览器复制粘贴
  9. 机会的度量:概率和分布
  10. CAS (3) —— Mac下配置CAS客户端经代理访问Tomcat CAS