zoukankan      html  css  js  c++  java
  • 用归并排序求逆序对

    相比树状数组求逆序对,归并排序的逻辑复杂度稍微小一点。


    首先我们来理解归并排序。首先用mergeSort将一个序列不断二分,直到每个子序列只有长度2

    然后递归到了栈底。我们再用merge函数,将递增有序的序列拼接起来。因为序列递增有序,所有时间复杂度为O( max(m+n) ),这里的m、n分别是两个序列的长度。加上二分,总的时间复杂度接近O(NlogN)

    在拼接的过程中,用a、b分别记录两个序列的索引,然后不断取其中最小的。最后用两个while循环,将还满足“未越界”的a或b循环变量遍历完。最后,将临时数组放到arr工作数组中。


    然后讨论怎样用这个过程求逆序数:

    假设我们有两个递增有序的序列A和B:

    A:1 3 5

    B:2 4

    循环取数的顺序是:1  3  5

    加粗的表示取到了B序列。而这一过程中统计的逆序数的数目,就是A的循环下标a的右端数的数目。

    这很好理解:3、5都比2(当前B序列的数)大,5比4(当前B序列的数)大

    牢记以上原则,就可以编写出求逆序对的代码。

    板子:

    int arr[LEN];
    int tmp[LEN];
    int ans=0;
    
    void merge(int s,int mid,int e){
        int i=0,a=s,b=mid+1,j=0;
        while(a<=mid && b<=e){
            if(arr[a]<=arr[b]){
                tmp[i++]=arr[a++];
            }else{
                tmp[i++]=arr[b++];
                ans+=mid-a+1;
            }
        }
        while(a<=mid) tmp[i++]=arr[a++];
        while(b<=e) tmp[i++]=arr[b++];
        FF(j,i) arr[s+j]=tmp[j];
    }
    
    void mergeSort(int s,int e){
        if(s<e){    //能够被划为。如果只有一个数就不能被划分 
            int mid=(s+e) /2;
            mergeSort(s,mid);
            mergeSort(mid+1,e);
            merge(s,mid,e);
        }
    }
  • 相关阅读:
    2.6
    20、算法的复杂度
    SVN的部署及分支等方法
    19、数据库设计的三大范式
    2.ViewBag、ViewData、TempData之间的区别
    1、MVC和EF中的 Model First 和 Code First
    19、lambda表达式树
    12、c#中事务及回滚
    11、Linq的使用
    18、(番外)匿名方法+lambda表达式
  • 原文地址:https://www.cnblogs.com/TQCAI/p/8641452.html
Copyright © 2011-2022 走看看