題目描述
在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數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
思路,如果我們暴力一點,可以直接嵌套雙遍歷進行獲取個數就完事了,可是這樣,每次都拿出一個數跟其他比較,複雜度太大:n^2。所以這裏使用了小套路:歸併排序。現將數組分解成單個元素,然後兩個相鄰的進行比較,如果前邊的打則符合條件,我們進行計數,並進行排序,防止下次重複計數。然後比較同一組的另外相鄰的兩個元素,同理。最後比較已兩個爲基本單位的兩個組合,進行混合比較同時計數和排序。說起來可能有點蒙,這裏爲了方便理解盜了張圖。這樣至少節省了一般以上的時間成本。
import java.util.*;
public class Solution {
int count = 0;
public int InversePairs(int [] array) {
mergeSort(array,0,array.length-1);
return count;
}
// 歸併排序開始,即遞歸形式把數組切割成單個元素,然後回馬槍開始排序同時統計count
public void mergeSort(int [] array,int lo,int hi){
if(lo==hi)return;
int mid = (lo+hi)>>1;
mergeSort(array,lo,mid);
mergeSort(array,mid+1,hi);
merge(array,lo,mid,hi);
}
public void merge(int [] array,int lo,int mid,int hi){
// k記錄當前輔助數組索引
// p1記錄左半段開始索引位置
// p2記錄右半段開始索引位置
int k = 0, p1 = lo,p2 = mid+1;
int [] copy = new int[hi-lo+1];
while(p1<=mid&&p2<=hi){
if(array[p1]>array[p2]){ // 前邊大,說明p1處至p2處中間這些數都能與p1位置處組成逆序對
count=(count+(mid-p1+1))%1000000007;
copy[k++] = array[p2++]; // 把較小的放入到輔助數組
}else{
copy[k++] = array[p1++];
}
}
// 將剩餘的賦值到輔助數組copy中
while(p1<=mid){
copy[k++] = array[p1++];
}
while(p2<=hi){
copy[k++] = array[p2++];
}
// 把輔助數組的值賦給相應位置的原數組,開始下次merge
for(int i = 0;i < k;i++){
array[i+lo] = copy[i];
}
}
}
- 時間複雜度:O(nlogn)。
- 空間複雜度:O(n)。