左神算法:求数组小和
题目描述:
在一个数组中,一个数左边比他小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。用归并排序思想解决
案例:[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
解题思想
左边比右边数小可以转变为右边比左边大的数,当进行归并排序时的merge操作时,当arr[p1]>=arr[p2]时,先让p2++;然后通过res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;来求出小数和。
代码
public class Code02_MergeLettcodeTest{
public static int smallNum(int[] arr) {
if (arr == null || arr.length < 2) {
return 0;
}
return processNum(arr,0,arr.length-1);
}
/**
* 所有merge时,产生的小数和,累加
* 左排序时 merge 右排序时merge
* @param arr
* @param L
* @param R
* @return
*/
public static int processNum(int[] arr, int L, int R) {
if (L == R) {
return 0;
}
int mid= L+((R-L)>>1);
return processNum(arr,L,mid)+processNum(arr,mid+1,R)+mergeNum(arr,L,mid,R);
}
public static int mergeNum(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] ? (r - p2 + 1) * arr[p1] : 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 (int j = 0; j <help.length ; j++) {
arr[l + j] = help[j];
}
return res;
}
public static void main(String[] args) {
int[] arr = new int[]{1, 3, 4, 2, 5};
System.out.println(smallNum(arr));
}
}