分治 | 求排列的逆序数

一、题目描述

描述

在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务。

对于不同的排名结果可以用逆序来评价它们之间的差异。考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。

一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

现给定1,2,…,n的一个排列,求它的逆序数。

输入

第一行是一个整数n,表示该排列有n个数(n <= 100000)。

第二行是n个不同的正整数,之间以空格隔开,表示该排列。

输出

输出该排列的逆序数。

样例输入

6 2 6 3 4 5 1

样例输出

8


此题目有两种解法(目前能想到的):

1.枚举:时间复杂度为O(n^2)
2.分治:时间复杂度为O(n*logn)

在此我们利用分治思想来解


思路:

类似于归并排序:

1.将数组分成两半,分别求出左半边的逆序数和右半边的逆序数
2.再算有多少逆序是由左半边取一个数和右半边取一个数构成
实际上就是归并排序的改造,即对此排列进行归并排序,边排序边计算它的逆序数

求逆序数的关键:

设左半边和右半边都是从小到大有序的(此时进行归并),从左到右依次扫描,比较两个各取一个数的大小,如果左边第一个数比右边第一个数大,那么左边排列的其他数字也可以和右边第一个数构成逆序数,以此类推。

代码如下:

#include <iostream>
using namespace std;
long long sum = 0;//逆序数的个数 
void MergeSort(int * arr,int s,int e,int *temp);//归并排序
void MergeAndCountNum(int * arr,int s,int mid,int e,int *temp); //归并有序序列并计算逆序数的个数 
int main(){
    int a[100001],b[100001],n;
    cin >> n;
    for(int i=0;i<n;++i)
        cin >> a[i];
    MergeSort(a,0,n-1,b);
    cout << sum ;
    return 0;
} 
 
void MergeSort(int * arr,int s,int e,int * temp){//归并排序 
    if(s < e){ 
        int mid = s + (e - s)/2;
        MergeSort(arr,s,mid,temp);
        MergeSort(arr,mid+1,e,temp);
        MergeAndCountNum(arr,s,mid,e,temp);
    }
}
void MergeAndCountNum(int * arr,int s,int mid,int e,int * temp){//归并有序序列并计算逆序数的个数 
    int p1 = s, p2 = mid +1,index = 0;
    while(p1 <= mid && p2 <= e){
        if(arr[p1] < arr[p2])
            temp[index++] = arr[p1++];
        else{
            temp[index++] = arr[p2++];
            sum += mid - p1 +1;
        }
    }
    while(p1 <= mid)
        temp[index++] = arr[p1++];
    while(p2 <= e)
        temp[index++] = arr[p2++];
    for(int i = 0;i<e - s +1;++i)
        arr[s+i] = temp[i];
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容

  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,690评论 0 13
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,729评论 0 15
  • 1 初级排序算法 排序算法关注的主要是重新排列数组元素,其中每个元素都有一个主键。排序算法是将所有元素主键按某种方...
    深度沉迷学习阅读 1,394评论 0 1
  • 问题描述 笨方法:O(n2) 分治O(nlogn) 1)将数组分成两半,分别求出左半边的逆序数和右半边的序数2)再...
    Co_zy阅读 893评论 0 1
  • 世上最好的生意就是向少年卖希望,向女人卖青春,向老人卖健康,以及向中产阶级兜售生活方式。
    关guan关guan阅读 172评论 0 0