数组中的逆序对

题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,有一个数组为Array[0..n] 其中有元素a[i],a[j].如果 当i<j时,a[i]>a[j],那么我们就称(a[i],a[j])为一个逆序对。在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。

归并排序O(n*logn)

题目1384:数组中的逆序对 http://ac.jobdu.com/problem.php?pid=1348

#include<iostream>
#include<stdlib.h>
#include<cstdio>
using namespace std;
const int maxn = 100001;
void printArray(int arry[],int len)
{
    for(int i=0;i<len;i++)
        cout<<arry[i]<<" ";
    cout<<endl;
}
int MergeArray(int arry[],int start,int mid,int end,int temp[])//数组的归并操作
{
    //int leftLen=mid-start+1;//arry[start...mid]左半段长度
    //int rightLlen=end-mid;//arry[mid+1...end]右半段长度
 
    int i=mid;
    int j=end;
    int k=0;//临时数组末尾坐标
    int count=0;
    //设定两个指针ij分别指向两段有序数组的头元素,将小的那一个放入到临时数组中去。
    while(i>=start&&j>mid)
    {
        if(arry[i]>arry[j])
        {
            temp[k++]=arry[i--];//从临时数组的最后一个位置开始排序
            count+=j-mid;//因为arry[mid+1...j...end]是有序的,如果arry[i]>arry[j],那么也大于arry[j]之前的元素,从a[mid+1...j]一共有j-(mid+1)+1=j-mid
             
        }
        else
        {
            temp[k++]=arry[j--];
        }
    }
    //cout<<"调用MergeArray时的count:"<<count<<endl;
    while(i>=start)//表示前半段数组中还有元素未放入临时数组
    {
        temp[k++]=arry[i--];
    }
 
    while(j>mid)
    {
        temp[k++]=arry[j--];
    }
 
    //将临时数组中的元素写回到原数组当中去。
    for(i=0;i<k;i++)
        arry[end-i]=temp[i];
 
    //printArray(arry,8);//输出进过一次归并以后的数组,用于理解整体过程
    return count;
 
}
//注意:inversions不能声明为int型,必须为long long型。
//因为题目中说数组最大为10^5,那么最大逆序对为(10^5-1)*10^5/2,这个数大约在50亿左右,超过了int型的表示范围。
long long InversePairsCore(int arry[],int start,int end,int temp[])
{
    long long inversions = 0;  
    if(start<end)
    {
        int mid=(start+end)/2;
        inversions+=InversePairsCore(arry,start,mid,temp);//找左半段的逆序对数目
        inversions+=InversePairsCore(arry,mid+1,end,temp);//找右半段的逆序对数目
        inversions+=MergeArray(arry,start,mid,end,temp);//在找完左右半段逆序对以后两段数组有序,然后找两段之间的逆序对。最小的逆序段只有一个元素。
    }    
    return inversions;
}
 
 
long long InversePairs(int arry[],int len)
{
    int *temp=new int[len];
    long long count=InversePairsCore(arry,0,len-1,temp);
    delete[] temp;
    return count;
}
int a[maxn];
int main()
{
    int n;
    while (scanf("%d",&n) == 1)
    {
        for (int i = 0; i < n; i++)
            scanf("%d",&a[i]);
        long long count = InversePairs(a,n);
        printf("%lld\n",count);
    }
     
    return 0;
}


参考: http://www.cnblogs.com/xwdreamer/archive/2012/10/12/2721938.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值