求數組中的逆序對的數量----劍指offer36題

在數組中的兩個數字,若是前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數:算法

如數組{7,5,6,4},逆序對總共有5對,{7,5},{7,6},{7,4},{5,4},{6,4};數組

思路1:暴力解法,順序掃描整個數組,每掃描到一個數字的時候,逐個比較該數字和它後面的數字的大小。若是後面的數字比它小,則這兩個數字就組成一個逆序對。假設數組中含有n個數字,因爲每一個數字都要和O(n)個數字做比較,所以這個算法的時間複雜度是O(n2)。spa

思路2:分治思想,採用歸併排序的思路來處理,以下圖,先分後治:code

 

先把數組分解成兩個長度爲2的子數組,再把這兩個子數組分解成兩個長度爲1的子數組。接下來一邊合併相鄰的子數組,一邊統計逆序對的數目。在第一對長度爲1的子數組{7}、{5}中7>5,所以(7,5)組成一個逆序對。一樣在第二對長度爲1的子數組{6},{4}中也有逆序對(6,4),因爲已經統計了這兩對子數組內部的逆序對,所以須要把這兩對子數組進行排序,避免在以後的統計過程當中重複統計。blog

逆序對的總數=左邊數組中的逆序對的數量+右邊數組中逆序對的數量+左右結合成新的順序數組時中出現的逆序對的數量;排序

總結統計數組逆序對的過程:先把數組分隔成子數組,先統計出子數組內部的逆序對的數目,而後再統計出兩個相鄰子數組之間的逆序對的數目。在統計逆序對的過程當中,還須要對數組進行排序,其實這個排序過程就是歸併排序的思路。class

代碼實現思路以下:im

//數組中的逆序對
    public static int InversePairs(int[] array){
        if(array==null||array.length<=1)
            return 0;
        int[] copy = new int[array.length];
        for(int i=0;i<array.length;i++){
            copy[i] = array[i];
        }
        return mergeCount(array, copy, 0, array.length-1);
    }
    
    public static int mergeCount(int[] array, int[] copy, int start, int end){
        if(start==end){
            copy[start] = array[start];
            return 0;
        }
        int mid = (start+end)>>1;
        int leftCount = mergeCount(copy, array, start, mid);
        int rightCount = mergeCount(copy, array, mid+1, end);
        
        int i = mid;//i初始化爲前半段最後一個數字的下標
        int j = end;//j初始化爲後半段最後一個數字的下標
        int index = end;//輔助數組複製的數組的最後一個數字的下標
        int count = 0;//計數--逆序對的數目
        while(i>=start&&j>=mid+1){
            if(array[i]>array[j]){
                copy[index--] = array[i--];
                count += j-mid;
            }else{
                copy[index--] = array[j--];
            }
        }
        for(;i>=start;i--){
            copy[index--] = array[i];
        }
        for(;j>=mid+1;j--){
            copy[index--] = array[j];
        }
        return leftCount+rightCount+count;
    }
相關文章
相關標籤/搜索