來源:劍指offer
逆序對定義:a[i]>a[j],其中i<j
思路:利用歸並排序的思想,先求前面一半數組的逆序數,再求后面一半數組的逆序數,然后求前面一半數組比后面一半數組中大的數的個數(也就是逆序數),這三個過程加起來就是整體的逆序數目了。
易錯點:第二個方法在歸並時,需要array的左右子數組是已排好序的數組,歸並的結果是得到排好序的數組copy。因此在遞歸調用iPairs時,方法的前2個參數是顛倒的,這樣得到的array才是排好序的。
比如第一次時用copy當輔助數組對array排序,第二次就正好反過來。
代碼:
package algorithm; public class InversePairs { public static int iPairs(int[] array) { if (array == null) throw new IllegalArgumentException(); // 創建輔助數組 int length = array.length; int[] copy = new int[length]; System.arraycopy(array, 0, copy, 0, length); int numberOfInversePairs = iPairs(array, copy, 0, length - 1); return numberOfInversePairs; } /** * @author Thanos * @param array 未歸並數組 * @param copy 用於存儲歸並后數據的數組 * @param begin 起始位置 * @param end 結束位置 * @return 逆序數 */ public static int iPairs(int[] array, int[] copy, int begin, int end) { if(begin == end) return 0; int mid = (begin + end) / 2; // 遞歸調用 int left = iPairs(copy, array, begin, mid); int right = iPairs(copy, array, mid + 1, end); // 歸並 int i = mid, j = end, pos = end; int count = 0; // 記錄相鄰子數組間逆序數 while(i >= begin && j >= mid + 1) { if(array[i] > array[j]) { copy[pos--] = array[i--]; count += j - mid; } else copy[pos--] = array[j--]; } while(i >= begin) copy[pos--] = array[i--]; while(j >= mid + 1) copy[pos--] = array[j--]; return left + right + count; } public static void main(String... args) { int test[] = { 7, 5, 1, 6, 4 }; int count = iPairs(test); System.out.println(count + " "); } }