用歸並排序求逆序對


相比樹狀數組求逆序對,歸並排序的邏輯復雜度稍微小一點。


 

首先我們來理解歸並排序。首先用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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM