- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
文字题解
小数就是在一个数组中,当右边的数大于左边的数,那么左边的这个数就是小数
利用归并排序实现
在归并排序执行过程中,默认长度为1的数组是没有小数的 再归并合并数组的过程中, 合并前,左边是有序的,右边也是有序的 统计数量/如果左数小于右数,则代表需要产生一个小和, ((R - p2) + 1)代表的是右边数组中大于当前p1的有多少个数, 这个时候左边数组是有序的,右边数组是有序的
代码实现
private static int smallSum(int[] arr) {
if (arr == null || arr.length < 2) {
return 0;
}
return mergeSort(arr, 0, arr.length - 1);
}
private static int mergeSort(int[] arr, int L, int R) {
if (L == R) {
return 0;
}
int mid = L + ((R - L) >> 1);
return mergeSort(arr, L, mid) +
mergeSort(arr, mid + 1, R)
+ merge(arr, L, mid, R);
}
private static int merge(int[] arr, int L, int mid, int R) {
int[] help = new int[(R - L) + 1];
int p1 = L;
int p2 = mid + 1;
int i = 0;
int res = 0;
while (p1 <= mid && p2 <= R) {
//如果左数小于右数,则代表需要产生一个小和,((R - p2) + 1)代表的是右边数组中大于当前p1的有多少个数,这个时候左边数组是有序的,右边数组是有序的
res += arr[p1] < arr[p2] ? arr[p1] * ((R - p2) + 1) : 0;
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
//将左边还剩下的数放到arr里面去
while (p1 <= mid) {
help[i++] = arr[p1++];
}
//将右边还剩下的数放到arr里面去
while (p2 <= R) {
help[i++] = arr[p2++];
}
//排序
for (int j = 0; j < help.length; j++) {
arr[L + j] = help[j];
}
return res;
}