zoukankan      html  css  js  c++  java
  • 求逆序对的几种方法

    第一种方法是使用归并排序的方法:

      

    #include<cstdio>
    #include<algorithm>
    #define maxn 1000
    using namespace std;
    int n,A[maxn],temp[maxn],ans;
    void merge(int L1,int R1,int L2,int R2)
    {
        int k=0,i=L1,j=L2;
        while(i<=R1 && j<=R2)
        {
            if(A[i]<=A[j]) temp[k++]=A[i++];
            else if(A[i]>A[j])
            {
                ans+=(R1-i+1);
                temp[k++]=A[j++];
            }
        }
        while(i<=R1) temp[k++]=A[i++];
        while(j<=R2) temp[k++]=A[j++];
        for(i=0;i<k;i++) A[L1+i]=temp[i];
    }
    void mergeSort(int L,int R)
    {
        if(L<R)
        {
            int mid = (L+R)/2;
            mergeSort(L,mid);
            mergeSort(mid+1,R);
            merge(L,mid,mid+1,R);
        }
    }
    int main(void)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&A[i]);
        mergeSort(0,n-1);
        printf("%d",ans);
        return 0;
    }

    第二种方法是使用树状数组的方法:

      假设有n个数(n<=100000)组成a1,a2,a3,....,an,题目要求完成两种操作100000次:

      1.能够查询某段区间的和;2.能够随时更新某个数的值。

      普通数组:使用普通数组存储n个数,这个时候查询某段区间的值的时间复杂度将非常的大;

      辅助数组:如果使用辅助数组sum存储n个数,那么区间的[i,j]的和就是sum[j]-sum[i-1],时间复杂度非常的低

           但是如果修改一个数组的元素,那么这个时候的修改的时间复杂度非常高。

      树状数组:能够存储一定的信息,查询和修改的时间复杂度较低,具有和线段树类似的优点。

           存储的n个元素用数组a存储,使用t数组作为树状数组。t[x]存储t[x]管辖的长度的数据的和,

           这里需要谈论t[x]管辖的长度length,我们设置length为2^k(k是x的二进制末尾0的个数),例如4的末尾有两个0,

           那么t[4]=a[1]+a[2]+a[3]+a[4], 5的末尾有0个0,那么t[5]=a[5].

           使用x&(-x)计算t[x]管辖的长度length.(或者使用x^(x-1)也是可以的)

           使用函数int sum(int k)计算a[1]+a[2]+...+a[k]的值。

           使用函数update(int k,int change)更新所有包含a[x]的t[i],让t[i]+=change;

    #include<cstdio>
    #define maxn 100010
    int n,a[maxn],t[maxn],ans;
    int sum(int k)
    {
        int s = 0;
        for(int i=k;i>0;i-=i&(-i)) s+=t[i];//所求的区间长度和 = 当前管线的区间和 + 剩下的区间长度和
        return s;
    }
    void update(int k,int change)
    {
        for(int i=k;i<=n;i+=i&(-i)) t[i]+=change;//每一次循环就是找到了下一个包含k的区间对应的t[i]
    }
    int main(void)
    {
        int num;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            a[num]++;
            update(num,1);
            ans+=i-sum(num);//sum(num)计算的是小于等于num的总数,当前总数i-sum(num)大于num的元素的个数,就是逆序的个数。
        } 
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    C++ STL 介绍
    C++多线程学习笔记 (CreateThread()与 _beginthreadex() )
    Spring轻量级开发---基础知识和初体验
    J2EE面试题
    SSH的优缺点比较
    Qt容器类总结
    Qt Creater使用技巧
    Visual Studio里使用Qt
    Qt的学习之路
    解决Github下载慢和下载失败问题
  • 原文地址:https://www.cnblogs.com/zuimeiyujianni/p/8727251.html
Copyright © 2011-2022 走看看