一、解题思路:
每个数去找右边比自己大的数的个数,每个数乘以右边比自己大的数的个数并加和。
二、关键过程:
在归并排序的过程中在每次递归的过程中数组会被持续分成若干个两组,当递归回来时,左边在归并时检测右组还剩下的个数,即大于左组数的个数(小于左侧的已经归并完成了),右组归并时不检测(因为对于右组来说,没有右边的数)。
三、 关键问题:
问:一组求完后该组就被排好序了,那么排序会影响求和吗?
答:不会!因为对于下一组来说上一组的左右都属于左组(或右组)。
问:排序的意义?
答:确定比左组大的数的操作是O(1)。
五、注意事项:
当左右两组merge时若是相同,则先归并右组方便左组确定大于其的个数。
六、 示例代码:
public static int smallSum(int[] arr){
if(arr == null || arr.length < 2){
return 0;
}
int left = 0;
int right = arr.length - 1;
return process(arr, left, right);
}
private static int process(int arr[], int left, int right){
if(left == right){
return 0;
}
int mid = left + ((right - left) >> 1);
return process(arr, left, mid) +
process(arr, mid + 1, right) +
merge(arr, left, right, mid);
}
private static int merge(int arr[], int left, int right, int mid){
int p1 = left;
int p2 = mid + 1;
int N = right - left + 1;
int k = 0;
int help[] = new int[N];
int res = 0;
while(p1 <= mid && p2 <= right){
if(arr[p1] < arr[p2]){
int num = right - p2 + 1;
res += num * arr[p1];
help[k++] = arr[p1++];
}else{
help[k++] = arr[p2++];
}
}
while(p1 <= mid){
help[k++] = arr[p1++];
}
while(p2 <= right){
help[k++] = arr[p2++];
}
for(int i = 0; i < N; i++){
arr[left++] = help[i];
}
return res;
}