O(n*lgn)时间复杂度的逆序对统计算法实现思想

逆序对定义:设A[1..n]是一个包含n个不同数的数组。如果在i<j的情况下,有A[i] > A[j],则(i,j)就称为A中的一个逆序对(inversion)。

现给出一个算法,其可以用O(n*lgn)的最坏情况运行时间,确定n个元素的任何排列中逆序对的数量。

简单的算法实现思想:我们可以单纯的通过从前往后的逐一比对来确定逆序对的数量,虽然实现简单,但这样一来时间复杂度将会上升为O(n*n),不符合我们的要求。

改进的算法实现思想:众所周知归并排序的时间复杂度为O(cn*lgn + cn),其中c为常数。因此我们可以通过对归并排序算法稍加改进来达到目的。即在每一次归并两个子数组的同时以左边的子数组的最大值为基准比对右边的子数组中的每个元素,只要左边子数组的最大值未复制回上层数组中,右边数组中所有已经复制到上层数组中的元素均对应一个逆序对,当左边子数组最大值被复制到上层后,如果右边子数组未复制完毕,则将右边最大子数组中的其余元素复制到上层对应位置,若右子数组已经复制完毕则不做任何操作,并终止当前层逆序对计数。例如在归并排序的某一层中有如下两个子序列:

左数组:2 5 9 12

右数组:3 7 7 19

由于左右数组都是有序的,那么当前层所有所有元素被复制回上层后共出现了3个逆序对,分别由右数组的3、7、7分别产生的,之后将右边子数组中的19复制到上层中。最终经层层处理最终可以统计出数组中逆序对的总数量。

时间复杂读分析:不难发现,求逆序对的时间和归并排序大体相当,为O(cn*lgn + cn).若c等于1则简化为O(n*lgn + n),也即O(n*(lgn + 1))。

时间: 2024-10-20 06:08:08

O(n*lgn)时间复杂度的逆序对统计算法实现思想的相关文章

51nod1779 逆序对统计

1779 逆序对统计 基准时间限制:1 秒 空间限制:131072 KB lyk最近计划按顺序做n道题目,每道题目都分为很多分数档次,lyk觉得这些题太简单了,于是它想到了一个好玩的游戏. lyk决定将每道题目做出其中的某个分数,使得这n道题目的逆序对个数最多. 为了方便,假设共有m个分数档次,并且会给m个分数档次分配一个题目编号,表示该题目会出现这个分数档次. 题目保证每道题都存在至少一个分数档次.(例如样例中5道题目的分数分别是5,6,3,4,7,共有4个逆序对) Input 第一行两个数n

[hdu5225]逆序对统计

题目:给定一个1到n的排列,求字典序小于这个排列的所有排列的逆序对数之和. 思路:既然是求字典序小于这个排列的,不妨将排列根据和它前k位相同来分类,然后枚举第k+1位的数(小于原序列第k+1位的数),假设逆序对的位置为(x,y),对于1<=x<k+1,x<y<=k+1和1<=x<=k+1,k+2<=y<=n的答案是容易计算出来的,对于k+2<=x<n,x<y<=n的答案则可以通过dp来计算由于剩余的数已没有大小意义了,假设剩余p个不同

P1908 逆序对——归并算法

先吐槽 这题做了两天,昨天讲分治,老师用归并讲了一遍,今天又用树状数组讲了一遍 归并不难,啊啊啊我居然才调出来 思路 归并两个数组时,对于第二个数组的元素a[c2],它与第一个数组中目前还没归到总数组里的元素形成逆序对 c1,c2是指针,对于a[c2],它与a[c1..mid]构成逆序对,贡献{mid - c1 + 1}对 注意 ans开longlong,不然会WA一半! 临时数组c开成全局变量,函数里放不下 两种记录方式 >函数不返回值,ans开成全局变量,在每次归并两个数组时增加对数 >函

51nod 1779逆序对统计(状压DP)

按照插入数的大小排序, 然后依次进行dp. 用一个状态表示n个数是否被选了 10110 就是表示第1.3.4个位置都选了 那么如果此时这个数该填到5这个位置,那么必定会造成一个逆序(因为下一个数会填到2,下一个数必定比这个数大) 也就是转移的时候看插入位置前有多少个0,进行转移 写的时候有一些小技巧 (直接用记忆化统计0的个数超时了,这里有一个递推的技巧) #include <iostream> #include <cstring> #include <cstdio>

归并排序及统计数组逆序对

 1.归并排序 <算法导论>P19 参考网址: 白话经典算法系列之五 归并排序的实现 - MoreWindows Blog - 博客频道 - CSDN.NET http://blog.csdn.net/morewindows/article/details/6678165 #include "stdafx.h" #include <iostream> using std::cout; #define ARRAY_LENGTH 11 //排序两个已经排好序的数

逆序对

什么是逆序对?? 我们在这里给出一个定义:如果i<j&&a[i]>a[j]的一对数称为逆序对. 为什么??!! 背过!!(都说了是定义了!)(其实我也不知道为什么  orz   (*^__^*) ……) 但是知道逆序对有什么用处呢? 具体用处我也不是很清楚,但是目前我们可以用逆序对的个数求将一列数排成有序的一列数交换的次数 怎样求逆序对呢?? 我们在这里给出两种算法:归并排序求逆序对:树状数组求逆序对. §归并排序求逆序对 归并排序的核心思想是二分. 我们将一个序列a1,a2,

SPOJ COWPIC(逆序对变形题)

SPOJ COWPIC 题目链接 题意:一个序列,相邻可以交换,问最少交换几次使得变成循环的1-n的其中一种 思路:对于原来正常的变换成1-n而言,答案就是逆序对了,而多了这么一个变形,其实只需要考虑一下,先求出变换成1-n的逆序对,然后如果原序列变成2, 3, 4 ... n, 1的话,等于是在原来的序列上,把每个数字模1加n之后求逆序对,那么对于这个新序列而言,只有原来最大的n变成了1会受影响,那么最大的n原来的逆序对就不在是逆序对,原来不是逆序对的就变成逆序对了,所以只要一开始记录下每个数

Day2:T4求逆序对(树状数组+归并排序)

T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*(); B[J]>=B[I] 也就是求逆序对: 求逆序对的方法主要有两种: 归并排序: 树状数组: 这里两种方法都学习一下: 1.之前对于树状数组的印象就只有单点修改和区间求和 一直觉得lowbit是一个神奇的东西(至今没有搞懂原理) 上网搜了一下用树状数组求逆序对的方法,发现有一个大神写的很棒....看

【BUAA 1246】数组中的逆序对

数组中的逆序对 归并算法的灵活运用 之前就听学长说这个用来算逆序对很好用 一直没有自己实现过 这次虽然比赛中没去做 赛后自己实现了出来 很有成就感! 也对归并算法透彻领悟了 真的好多算法都需要理解 而不是死记硬背 之前就是硬背过的 过一段时间就忘光了 这次彻底明白了算法执行过程 比起做出这道题 更宝贵 代码如下 #include <bits/stdc++.h> #define LL long long using namespace std; int num[111111]; int n[11