劍指Offer - 陣列中的逆序對(Java實現)
阿新 • • 發佈:2019-01-02
題目描述:
在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個陣列中的逆序對的總數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;
}
}