计算数组的逆序对个数

问题:给定一个数组A,A存有n个互不相同的整数。定义:若i<j且A[i]>A[j],则称(i,j)为A的一个逆序对(inversation)。设计一个O(nlogn)算法求A中逆序对个数。

显然最坏情况下逆序对有n(n-1)/2个,如;5 4 3 2 1完全逆序,逆序对有(5-1)*5/2=10对。若用暴力来求解,则时间复杂度为O(n2),显然比这不是一个好的算法。下面考虑用归并排序的类似方法来解决这个问题。

首先,对于一个长度为n的数组A[0...n-1],我们可以将它分为两个长度为n/2子数组L[0...n1]=A[0...n/2]和R[0...n2]=A[n/2+1...n-1],总的逆序对=L中的逆序对+R中的逆序对+横扫L和R的逆序对

比如将数组 2 3 8 6 1分为两部分 L: 2 3 8和 R:6 1,于是左边L中逆序对0个,右边R中逆序对(6,1)共1对,那么横扫L与R的有(2,1),(3,1),(8,6),(8,1)一共4对,于是总的对数为0+1+4=5对。现在问题的难点就是如何求中间横扫那部分的逆序对,如果暴力来求,必然O(n2)。我们先来看看这样的一个事实,如果将L排好序,将R也排好序,这时候中间横扫那部分的逆序对个数不会改变,这是因为L与R是分开的。这样以来,我们可以用归并排序的思路设计这个算法,基于这样设计之所以正确在于每一次子序列的排序的归并都是在该该序列逆序对计算完成后进行的。C++代码如下:

#include<iostream>
using namespace std;
#define MAX_VALUE 12343564
int Count_Reversations(int *A, int n);
int Merge_Reversations(int *A, int p, int r);
int main(){
     int a[5] = { 2,3,8,6,1 };
     cout << Count_Reversations(a, 5) << endl;
     return 0;
}
int Count_Reversations(int*A, int n){ //接口函数
     return Merge_Reversations(A, 0, n - 1);
}
int Merge_Reversations(int *A, int p, int r){
     if (p>=r)
          return 0;
     int i, j, k,mid,n1,n2, reversations = 0;
     mid = (p + r) >> 1;
     int next_count= Merge_Reversations(A, p, mid) + Merge_Reversations(A, mid + 1, r);
     n1 = mid - p + 1;
     n2 = r - mid;
     int *R = new int[n2 + 1];
     int *L = new int[n1 + 1];
     for (i = 0; i < n1; i++)
          L[i] = A[i + p];
     for (j = 0; j < n2; j++)
          R[j] = A[j + mid + 1];
     L[n1] = R[n2] = MAX_VALUE; //设置为最大值,当做哨兵
     i = j = 0;
     for (k = p; k <= r; k++){
          if (L[i]>R[j]){
                 reversations +=n1-i;
                 A[k] = R[j++];
     }
     else
         A[k] = L[i++];
}
    delete[]R, L;
    return reversations +next_count;
}

时间: 2024-10-23 21:21:48

计算数组的逆序对个数的相关文章

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[J]>=B[I] 之后就是求逆序对的事情了 然后这里学一下用树状数组的方法 原理是:树状数组是用来求区间和的是吧 就是按权值的区间统计那么可以BIT维护...然后扫一遍 也就是计算有多少个逆序对 按权值的区间统计就是记录数的个数

树状数组求逆序对

给定n个数,要求这些数构成的逆序对的个数.除了用归并排序来求逆序对个数,还可以使用树状数组来求解.树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了.把所有的加起来就是总的逆序对数.题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000.如果采用上面的思想,必然会导致空间的巨大浪费,而且由

hdu5792 World is Exploding(多校第五场)树状数组求逆序对 离散化

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5792 题目描述:给你n个值,每个值用A[i]表示,然后问你能否找到多少组(a,b,c,d)四个编号,四个编号互不相同,然后a < b, c < d,a代表的值小于b代表的值,c代表的值大于d代表的值. 解题思路:先考虑a和b这两个编号,遍历每一个编号作为b,然后找到b前面有多少个小于b的值,就是对于这一个编号b合理的编号a,对于每一组a和b,就可以考虑c和d,能够满足条件c和d的很显然就是除去a和

P1136 归并排序,求逆序对个数

这道题从看到它开始到做出来,已经过了快两周[因为第一次思路完全跑偏写的是暴力模拟想水过]: 题意是这样的:  jzabc除了对多米诺骨牌感兴趣外,对赛车也很感兴趣.上个周末他观看了一场赛车比赛.他总是能想出许多稀奇的问题.某一时刻,他看到有n辆车(总是匀速行驶)在同一直线上,并且处在一个无限长度的直道上,而且n辆车有严格的先后之分.他通过特殊的器材测出了每一辆车的速度.那么问题出现了,如果有两辆车A车和B车,A车在B车的后面,并且A车的速度比B车的快,那么经过一段时间后,A车一定会超过B车.我们

逆序对个数 - 冒泡排序

设一个序列为: a[0], a[1], ..., a[n-1],一个逆序对是指:{ (a[i], a[j]) | a[i] > a[j], i < j }. 统计一个序列中的逆序对个数,可以使用冒泡排序法.二路归并法等.这里介绍利用冒泡排序统计逆序对个数的方法. 核心思想:冒泡排序中,每进行一次交换,则序列的逆序对个数-1. 证明:设冒泡排序过程中 a[i] 与 a[i+1] 进行了一次交换,这说明 a[i] > a[i+1].序列中逆序对可分为四种:① 非 a[i] 和非 a[i+1]

【bzoj2789】[Poi2012]Letters 树状数组求逆序对

题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度. 第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母. 输出 一个非负整数,表示最少的交换次数. 样例输入 3 ABC BCA 样例输出 2 题解 树状数组求逆序对 一个结论:将序列A通过交换相邻元素变换为序列B,需要的最小次数为A中

蓝桥杯小朋友排队(树状数组求逆序对)

居然存在身高为0的数据... 树状数组求逆序对原理: add(h[j],1); //将身高为h[j]的数据的出现次数加1 sum(h[j]);//求i<j 且 h[i] <=h[j] 的数据出现次数之和  那么 i-sum(h[j]) 为 i > j 且 h[i] > h[j] 数据的出现次数之和 即为 逆序对数 #include"cstdio" #include"cstring" #define lowbit(i) i&(-i) u

SGU180(树状数组,逆序对,离散)

Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: standard There are N integers (1<=N<=65537) A1, A2,.. AN (0<=Ai<=10^9). You need to find amount of such pairs (i, j) that 1<=i<j<=N and A

HDU 1394 树状数组求逆序对

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13036    Accepted Submission(s): 7968 Problem Description The inversion number of a given number sequence a1, a2, ..., an