1. 程式人生 > >歸併排序--小和問題(逆序對)

歸併排序--小和問題(逆序對)

引言

    求小和問題:在隨機元素,隨機陣列大小的陣列中,找出左邊比右邊元素小的所有元素之和。

    例如:陣列[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;
	}
	
}
以上就是求最小和問題程式碼,在左右陣列進行合併的時候來進行計算小和。也可以在此基礎上求取逆序對,具體請看註釋。