逆序数【东北大学oj数据结构5-4】C语言

对于给定的序列A={a0​,a1​,…,an−1​},若二元组(i,j)满足ai​>aj​,i<j则称(i,j)为一个逆序。给定序列中逆序的数量称为该序列的逆序数。 可以证明,逆序数等于以下程序中定义的冒泡排序的交换次数:

bubbleSort(A)
cnt = 0 // the number of inversions
for i = 0 to A.length-1
    for j = A.length-1 downto i+1
        if A[j] < A[j-1]
            swap(A[j], A[j-1])
        cnt++
return cnt

对于给定的序列A,打印A的逆序数。注意不要使用上面的程序,这会导致程序运行超时。

输入
在第一行中,给出了一个整数 n,即 A 中元素的数量。
在第二行中,元素ai​(i=0,1,…,n−1)由空格字符分隔。

输出
打印逆序数。

约束
1≤n≤200,000
0≤ai​≤10^9
ai​都不同

 输入样例

5
3 5 2 1 4

输出样例 

 题目中给出提示,在排序中计算逆序数

由于冒泡排序的时间复杂度是O(n^2),所以我们要选择更好的排序方法

我们选择归并排序O(nlogn),直接把上一道题中的代码拿过来用就行

c变为逆序数,当我们选择右侧R[j]并放入合并后的数组时,左侧L[]中剩下的所有元素都大于R[j]

所以,c+=(n1-i)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
long long c=0;
void Merge(int * a,int left,int mid,int right)
{
    int n1=mid-left;
    int n2=right-mid;
    int *L=(int*)malloc((n1+1)*sizeof(int));
    int *R=(int*)malloc((n2+1)*sizeof(int));
    for(int i=0;i<n1;i++)
    {
        L[i]=a[left+i];
    }
    for(int i=0;i<n2;i++)
    {
        R[i]=a[mid+i];
    }
    L[n1]=__INT_MAX__;
    R[n2]=__INT_MAX__;
    int i=0,j=0;
    for(int k=left;k<right;k++)
    {
        if(L[i]<=R[j])
        {
            a[k]=L[i];
            i++;
        }
        else
        {
            a[k]=R[j];
            c+=(n1-i);
            j++;
        }
    }
    free(L);
    free(R);
}
void MergeSort(int * a,int left,int right)
{
    if(left+1<right)
    {
        int mid=(left+right)/2;
        MergeSort(a,left,mid);
        MergeSort(a,mid,right);
        Merge(a,left,mid,right);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    int *a=(int *)malloc(n*sizeof(int));
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    MergeSort(a,0,n);
    printf("\n%lld",c);
    free(a);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值