題目描述:
在數組中的兩個數字,如果前面一個數字大於后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007。
輸入描述:
題目保證輸入的數組中沒有的相同的數字數據范圍:
- 對於%50的數據,size<=10^4
- 對於%75的數據,size<=10^5
- 對於%100的數據,size<=2*10^5
解題思路:
本題一個最容易想到的解法是暴力解法,順序掃描整個數組,每掃描到一個數字時,逐個比較該數字與后面的數字的大小關系,統計逆序對的個數,假設數組中有n個數字,則每個數字都要和O(n)個數字做比較,因此,這個暴力解法的時間復雜度為O(n^2)。
一般情況下,最容易想到的往往不是最優解法。在這里,我們采用分治的思想,類比歸並排序算法來分析此題。
首先將數組分隔成子數組,統計出子數組內部逆序對數目,然后再統計相鄰子數組之間的逆序對數目,統計過程中還需要對數組進行排序,這實際上就是歸並排序的過程。主要考慮的是合並兩個有序序列時,計算逆序對數。對於兩個有序升序序列,設置兩個下標分別指向開始位置,每次比較兩個指針對應的值,如果第一個序列當前值大於第二個序列當前值,則有第一個序列“當前長度”個逆序對。
這看起來好像比較拗口,但是從代碼中可以直觀看出。
舉例:
編程實現(Java):
public class Solution {
int res=0;
public int InversePairs(int [] array) {
//數組中的逆序對,歸並排序
if(array==null || array.length==0)
return 0;
findInversePairs(array,0,array.length-1);
return res%1000000007;
}
public void findInversePairs(int[] array,int low,int high){
if(low<high){
int mid=low+(high-low)/2;
findInversePairs(array,low,mid); //左一半遞歸
findInversePairs(array,mid+1,high); //右一半遞歸
//merge
merge(array,low,mid,high);
}
}
public void merge(int[] array,int low,int mid,int high){
int i=low,j=mid+1;
int[] temp=new int[high-low+1];
int k=0;
while(i<=mid && j<=high){
if(array[i]<=array[j])
temp[k++]=array[i++];
else { //大於,說明是逆序
temp[k++] = array[j++];
res += (mid - i + 1);
res = res%1000000007;
}
}
while(i<=mid)
temp[k++]=array[i++];
while(j<=high)
temp[k++]=array[j++];
for(i=0;i<temp.length;i++)
array[low+i]=temp[i];
}
}
