求逆序对的方法之一 利用归并排序

归并排序:

可以参考别人的文章:https://zhuanlan.zhihu.com/p/36075856

我复制了一部分如下

归并排序的主要思想是分治法。主要过程是:

  1. 将n个元素从中间切开,分成两部分。(左边可能比右边多1个数)
  2. 将步骤1分成的两部分,再分别进行递归分解。直到所有部分的元素个数都为1。
  3. 从最底层开始逐步合并两个排好序的数列。

 

思考

考虑一个问题,如何将两个有序数列合并成一个有序数列?

很简单,由于两个数列都已经有序,我们只需从两个数列的低位轮番拿出各自最小的数来PK就就行了,输的一方为小值,将这个值放入临时数列,然后输的一方继续拿出一个值来PK,直至有一方没有元素后,将另一方的所有元素依次接在临时数列后面即可。此时,临时数列为两个数列的有序合并。归并排序中的归并就是利用这种思想。对应的代码如下:

/**
 * 合并两个有序数列
 * array[first]~array[mid]为第一组
 * array[mid+1]~array[last]为第二组
 * temp[]为存放两组比较结果的临时数组
 */
private static void mergeArray(int array[], int first, int mid, int last, int temp[]) {
    int i = first, j = mid + 1; // i为第一组的起点, j为第二组的起点
    int m = mid, n = last; // m为第一组的终点, n为第二组的终点
    int k = 0; // k用于指向temp数组当前放到哪个位置
    while (i <= m && j <= n) { // 将两个有序序列循环比较, 填入数组temp
        if (array[i] <= array[j])
            temp[k++] = array[i++];
        else
            temp[k++] = array[j++];
    }
    while (i <= m) { // 如果比较完毕, 第一组还有数剩下, 则全部填入temp
        temp[k++] = array[i++];
    }
    while (j <= n) {// 如果比较完毕, 第二组还有数剩下, 则全部填入temp
        temp[k++] = array[j++];
    }
    for (i = 0; i < k; i++) {// 将排好序的数填回到array数组的对应位置
        array[first + i] = temp[i];
    }
}

然后关键在于求其思想求逆元,如果你看完归并排序你会发现这个不就是求逆元的定义吗,只用对其进行数字统计就行了,进行一个累加的过程就可以了,因此可以看下题

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

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

输入格式

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

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

输出格式

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

数据范围

1≤n≤1000001≤n≤100000

输入样例:

6
2 3 4 5 6 1

输出样例:

5

 AC的代码

#include <bits/stdc++.h>
using namespace std;
long long sum=0;
void Merge(int a[],int left,int mid,int right,int c[])
{
    int i=left;
    int j=mid+1;
    int k=left;
    while(i<=mid&&j<=right)
    {
        if(a[i]<=a[j])
        {
            c[k++]=a[i++];
        }
        else
        {
            c[k++]=a[j++];
            sum+=mid-i+1;
        }
    }
    while(i<=mid)
    {
        c[k++]=a[i++];
    }
    while(j<=right)
    {
        c[k++]=a[j++];
    }
    for(int i=left;i<=right;i++)
    {
        a[i]=c[i];
    }
}
void Mergosort(int a[],int left,int right,int c[])
{
    if(left<right)
    {
        int mid=(left+right)/2;
        Mergosort(a,left,mid,c);
        Mergosort(a,mid+1,right,c);
        Merge(a,left,mid,right,c);
    }
}
int a[100000+10],c[100000+10];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    Mergosort(a,0,n-1,c);
    cout<<sum<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值