問題描述
在一個數組中, 每一個數左邊比當前數小的數累加起來, 叫做這個數組的小和。 求一個數組的小和。
樣例
[1,3,4,2,5]
1左邊比1小的數, 沒有;
3左邊比3小的數, 1;
4左邊比4小的數, 1、 3;
2左邊比2小的數, 1;
5左邊比5小的數, 1、 3、 4、 2;
所以小和爲1+1+3+1+1+3+4+2=16
題解
- 對數組進行歸併排序,在合併的過程中,如果左側部分的當前元素l小於右側部分的當前元素r,那麼計算右側部分當前位置到結束位置的元素個數,即爲兩部分合並之後的數組中在i右側的元素個數;否則右側指針下移。
- 不會出現重複計算的情況,因爲每次都是各部分之間比較,內部並不進行比較。
public static int smallSum(int[] arr) {
if(arr==null||arr.length<2)
return 0;
return smallSum(arr,0,arr.length-1);
}
private static int smallSum(int[] arr, int i, int j) {
if(i==j)
return 0;
int mid=i+(j-i)/2;
return smallSum(arr,i,mid)+smallSum(arr,mid+1,j)+mergeSum(arr,i,j,mid);
}
private static int mergeSum(int[] arr, int i, int j, int mid) {
int s=0;
int ii=i,ij=mid+1;
int []help=new int[j-i+1];
int k=0;
while(ii<=mid&&ij<=j) {
if(arr[ii]<arr[ij]) {
s+=(j-ij+1)*arr[ii];
help[k++]=arr[ii++];
}else {
help[k++]=arr[ij++];
}
}
while(ii<=mid)
help[k++]=arr[ii++];
while(ij<=j)
help[k++]=arr[ij++];
for(k=0;k<help.length;k++) {
arr[i+k]=help[k];
}
return s;
}
應用2:在一個數組中, 左邊的數如果比右邊的數大, 則折兩個數構成一個逆序對, 請打印所有逆序對