本文參考自《劍指offer》一書,代碼采用Java語言。
題目
在數組中的兩個數字如果前面一個數字大於后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。
思路
如果遍歷數組,對每個數字都和后面的數字比較大小,時間復雜度為O(n^2),效率太低。
利用歸並排序的思想,先將數組分解成為n個長度為1的子數組,然后進行兩兩合並同時排好順序。
在對兩個子區域合並排序時,記左邊區域(下標為start~mid)的指針為i,右邊區域(下標為mid+1~end)的指針為j,兩個指針都指向該區域內最大的數字,排序時:
(1)如果i指向的數字大於j指向的數字,說明:逆序對有j-mid個,我們把i指向的數字放入臨時創建的排序數組中,然后令i-1,指向該區域前一個數字,繼續進行排序;
(2)如果i指向的數字小於等於j指向的數字,說明暫時不存在逆序對,將j指向的數字放入臨時創建的排序數組中,然后令j-1,指向該區域前一個數字,繼續進行排序;
(3)某一子區域數字都放入排序數組后,將另一個子區域剩下的數字放入排序數組中,完成排序;
(4)最后將排序好的數字按順序賦值給原始數組的兩個子區域,以便合並后的區域與別的區域合並。

測試算例
1.功能測試(普通數組,遞增數組,遞減數組,含重復數字)
2.邊界值測試(數組只有兩個數字,只有一個數字)
2.特殊測試(null)
Java代碼、
//題目:在數組中的兩個數字如果前面一個數字大於后面的數字,則這兩個數字組
//成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。
public class InversePairs {
public static int inversePairs(int [] array) {
if(array==null || array.length<=0)
return 0;
int count=getCount(array,0,array.length-1);
return count;
}
private static int getCount(int[] array,int start,int end){
if(start>=end)
return 0;
int mid=(end+start)>>1;
int left=getCount(array,start,mid);
int right=getCount(array,mid+1,end);
//合並
int count=0;
int i=mid; //左邊區域的指針
int j=end; //右邊區域的指針
int[] temp= new int[end-start+1]; //臨時區域
int k=end-start; //臨時區域的指針
while(i>=start && j>=mid+1){
if(array[i]>array[j]){
count+=(j-mid);
temp[k--]=array[i--];
}else{
temp[k--]=array[j--];
}
}
while(i>=start)
temp[k--]=array[i--];
while(j>=mid+1)
temp[k--]=array[j--];
for(k=0;k<temp.length;k++)
array[k+start]=temp[k];
return count+left+right;
}
}
收獲
1.要對歸並排序的實現非常熟練。
