版权声明:Please make the source marked https://blog.csdn.net/qq_31807385/article/details/86318425
题目:
小和问题:在一个数组中,每一个数左边比当前小的数累加起来,叫做这数组的小和,求一个数组的小和,如:
【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 + 1 + 2 + 3 + 3, + 4 = 16
代码实现与分析:
package com.isea.brush;
/**
* 小和问题:
* 解题思路:利用归并排序的思想,假定左右补分都是有序的,然后在将左右部分merge有序
* 在merge的过程中,计算小和
*/
public class SmallSum {
public static void main(String[] args) {
}
public static int smallSum(int[] arr) {
if (arr.length < 2 || arr == null) {
return 0;
}
return mergeSort(arr, 0, arr.length - 1);
}
/**
* 在L-R的范围内会产生多少小和
* 这个过程,搜集左半部分的小和,右半部分的小和,加上左右merge的小和,也就是在每次merge的时候,计算小和
*
* @param arr
* @param L
* @param R
* @return
*/
private static int mergeSort(int[] arr, int L, int R) {
if (L == R) {
return 0;
}
int mid = L + (R - L) / 2;
return mergeSort(arr, L, mid) +
mergeSort(arr, mid + 1, R) +
merge(arr, L, mid, R);
}
/**
* 归并排序的过程中,merge的过程,左右两个指针,然后一个辅助数组,
* 对比左右数组中元素的大小,将其填入到辅助数组中
*
* @param arr
* @param L
* @param mid
* @param R
* @return
*/
private static int merge(int[] arr, int L, int mid, int R) {
int[] help = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = mid + 1;
int res = 0;
while (p1 <= mid && p2 <= R) {
res = arr[p1] < arr[p2] ? arr[p1] * (R - p2 + 1) : 0;
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= mid) {
help[i++] = arr[p1++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
return res;
}
}