1. 程式人生 > >劍指Offer - 陣列中的逆序對(Java實現)

劍指Offer - 陣列中的逆序對(Java實現)

題目描述:

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

示例

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

思路分析:
方法1:
遍歷陣列,依次找出後面小於的數。該方法屬於暴力查詢,時間複雜度O(N^2),執行超時。

public class Solution {
    public int InversePairs(int [] array) {
        
        if(array == null || array.length < 2){
            return 0;
        }
        int temp = 0;
        for(int i = 0 ; i<array.length-1; i++){
            for(int j = i+1 ; j < array.length ; j++){
                if(array[i]>array[j]){
                    temp++;
                }
            }
        }
        return temp%1000000007;
    }
}

方法2:
利用歸併排序的思想解決問題。
歸併排序的思想是分而治之,將陣列分為兩段,每段分別排序,再將兩段排序後的陣列組合在一起形成最終的陣列。
故,我們先記錄第一段沒有排序之前時,出現的逆序對的個數。以及第二段原陣列出現逆序對的個數。再計算兩段陣列之間出現的逆序對的個數。三者之和即為求得的最終結果。
重點是如何計算兩段陣列之間出現的逆序對。
1,設定兩個指標分別指向兩段陣列的末尾(p1表示前一段陣列的指標,p2表示後一段陣列的指標),再新建一個輔助陣列,長度是兩段陣列之和。
2,比較p1和p2位置數字的大小,若arr1[p1]>arr2[p2],則p2之前的所有數字均小於p1,該值也就是p1形成的逆序對,並將arr1[p1]放入輔助陣列的末尾,p1向前移動一位。若arr1[p1]<arr2[p2],則將p2指標所指的數字存入輔助陣列,p2指標向前移動一位。後面的思路和歸併排序就是一樣了。

public class Solution {
    
    //嘗試歸併排序的思想。
    public int InversePairs(int [] array) {
        
        if(array == null || array.length < 2){
            return 0;
        }
        int num = merge(array,0,array.length-1);
        return num%1000000007;
    }
    public int merge(int[] arr , int l, int r){
        if(r<=l){
            return 0;
        }
        int mid =(l+r)/2;
        int leftnum = merge(arr,l,mid)%1000000007;
        int rightnum = merge(arr,mid+1,r)%1000000007;
        int mergenum = mergeSort(arr,l,mid,r);
        return (leftnum+rightnum+mergenum)%1000000007;
    }
    public int mergeSort(int[] arr, int l, int m, int r){
        int[] help = new int[r-l+1];
        int h = r-l;
        int p1 = m;
        int p2 = r;
        int count = 0;
        while(p1>=l && p2>m){
            if(arr[p1]>arr[p2]){
                count += p2-m;
                if(count>=1000000007){
                    count%=1000000007;
                }
                help[h--] = arr[p1--];
            }else{
                help[h--] = arr[p2--];
            }
        }
        while(p1>=l){
            help[h--] = arr[p1--];
        }
        while(p2>m){
            help[h--] = arr[p2--];
        }
        for(int i = 0 ; i < help.length; i++){
            arr[l+i] = help[i];
        }
        return count;
    }
}
public class Solution {
    
    //嘗試歸併排序的思想。
    public int InversePairs(int [] array) {
        
        if(array == null || array.length < 2){
            return 0;
        }
        int[] help = new int[array.length];
        int num = merge(array,help,0,array.length-1);
        return num%1000000007;
    }
    public int merge(int[] arr ,int[] help ,int l, int r){
        if(r<=l){
            return 0;
        }
        int mid =(l+r)/2;
        int leftnum = merge(arr,help,l,mid)%1000000007;
        int rightnum = merge(arr,help,mid+1,r)%1000000007;
        int mergenum = mergeSort(arr,help,l,mid,r);
        return (leftnum+rightnum+mergenum)%1000000007;
    }
    public int mergeSort(int[] arr, int[] help, int l, int m, int r){
        int h = r;
        int p1 = m;
        int p2 = r;
        int count = 0;
        while(p1>=l && p2>m){
            if(arr[p1]>arr[p2]){
                count += p2-m;
                if(count>=1000000007){
                    count%=1000000007;
                }
                help[h--] = arr[p1--];
            }else{
                help[h--] = arr[p2--];
            }
        }
        while(p1>=l){
            help[h--] = arr[p1--];
        }
        while(p2>m){
            help[h--] = arr[p2--];
        }
        for(int i = l ; i <= r; i++){
            arr[i] = help[i];
        }
        return count;
    }
}