左神基礎班02、陣列中的逆序對

驕傲不死2017發表於2020-10-25

題目描述:

     在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個陣列,求出這個陣列中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007

輸入描述:

題目保證輸入的陣列中沒有的相同的數字
資料範圍:

對於%50的資料,size<=10^4

對於%75的資料,size<=10^5

對於%100的資料,size<=2*10^5

示例1:

輸入
1,2,3,4,5,6,7,0

輸出
7

原題連結:陣列中的逆序對

解題思路:

1、歸併排序 + 遞迴:

      可以利用歸併排序的思想,基本過程和歸併排序一樣,只不過在合併兩個子陣列時統計逆序對數量即可。設兩個排好序(逆序)的子陣列分別為arr[l,mid]和arr[mid + 1,l],指標p1和p2分別指向左右子陣列中的元素。具體的計算小和過程如下:

(1)當arr[p1] > arr[p2]時,則計算逆序對的數量,計算方式為res += r - p2 + 1,並將arr[p1]賦值給輔助陣列help: help[i++] = arr[p1]

(2)當arr[p1] <= arr[p2]時,則不用計算小和,直接將arr[p2]賦值給輔助陣列help: help[i++] = arr[p2]

遞迴終止條件:l == r,返回0。

注:(1)在每一步完成統計完逆序對的數量後,記得進行取餘操作。

時間複雜度和空間複雜度: 時間複雜度為O(NlogN),空間複雜度為O(N)

實現程式碼:

public class Solution {

	//解法1:歸併排序 + 遞迴
    public int InversePairs(int [] array) {
        if(array == null || array.length < 2)
            return 0;
        return inverseMerge(array, 0, array.length - 1);
    }
    
    public int inverseMerge(int[] arr, int l, int r){
        if(l == r)
            return 0;
        int mid = l + ((r - l) >> 1);
        int res = 0;
        //注意這裡每一步都要取餘
        res = (res + inverseMerge(arr, l, mid)) % 1000000007;
        res = (res + inverseMerge(arr, mid + 1, r)) % 1000000007;
        res = (res + merge(arr, l, mid, r)) % 1000000007;
        return res;
    }
    
    public int merge(int[] arr, int l, int mid, int r){
        int res = 0, i = 0;
        int p1 = l, p2 = mid + 1;
        int[] help = new int[r - l + 1];
        while(p1 <= mid && p2 <= r){
            res = (res + (arr[p1] > arr[p2] ? r - p2 + 1 : 0)) % 1000000007;
            help[i++] = arr[p1] > arr[p2] ? arr[p1++] : arr[p2++];
        }    
        while(p1 <= mid){
            help[i++] = arr[p1++];
        }
        while(p2 <= r){
            help[i++] = arr[p2++];
        }
        for(i = 0; i < help.length; ++i){
            arr[l + i] = help[i];
        }
        return res;
    }
}

相關文章