歸併排序--小和問題(逆序對)
阿新 • • 發佈:2019-01-25
引言
求小和問題:在隨機元素,隨機陣列大小的陣列中,找出左邊比右邊元素小的所有元素之和。
例如:陣列[4,2,5,1,7,3,6] 第一個元素4比2大,不算小和,5比4和2都大,那就是4+2=6;1比4和2和5都小,不算小和;7比前面的都大,那就是上次小和6+4+2+5+1=18;然後3前面比2和1大,那就是18+2+1=21;最後6比4、2、5、1、3都大,結果就是21+4+2+5+1+3=36。那麼最後的結果就是36。
解法:使用歸併排序來進行求和,在歸併的時候把陣列分成左右兩個,在歸併排序進行左右兩個陣列進行合併排序的時候進行計算。如果左邊陣列元素N,小於右邊陣列元素M,那麼從右邊陣列右指標P到右邊陣列最後R就有(R-P+1)個N,依次累計相加,最後求出最小和。
如果要求逆序對,所謂逆序對就是[4,2],[4,1],[5,1]....., 那麼就是左邊比右邊大,那麼有多少個逆序對就是,中間位置mid減去左指標下座標P1+1個逆序對,也就是(mid-P1+1)個逆序對,把逆序對相加進行返回就是共有多少逆序對。
以上就是求最小和問題程式碼,在左右陣列進行合併的時候來進行計算小和。也可以在此基礎上求取逆序對,具體請看註釋。public class MergeSortSum { public static int mergeSortSum(int[] arr){ if(null == arr || arr.length < 2){ return 0; } // 排序並返回最小和 return mergeSortSumTest(arr,0,arr.length-1); } public static int mergeSortSumTest(int[] arr, int L, int R) { if(L == R ) { return 0; } int mid = L + (R -L) /2; // 左邊的最小和+右邊的最小和+最後排序好的最小和就是最後的結果 return mergeSortSumTest(arr, L, mid) + mergeSortSumTest(arr, mid+1, R) + mergeSortSumArray(arr,L,mid,R); } public static int mergeSortSumArray(int[] arr, int l, int mid, int r) { int[] arrs = new int[r-l+1]; int i = 0; int p1 = l; int p2 = mid + 1; int sum = 0;// 最小和 while(p1<=mid && p2 <= r){ // 如果左邊小於右邊,那就有(r - p2 + 1)個arr[p1]元素的和是最小和 // 如果大於右邊,返回0 sum += arr[p1] < arr[p2]?(r - p2 + 1)*arr[p1]:0; // sum += arr[p1] > arr[p2]?(mid - p1 + 1):0; //求逆序對 arrs[i++] = arr[p1] < arr[p2]?arr[p1++]:arr[p2]; } while(p1<=mid){ arrs[i++] = arr[p1++]; } while(p2<=r){ arrs[i++] = arr[p2++]; } return sum; } }