本文參考自《劍指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.要對歸並排序的實現非常熟練。