本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。
题目思路
这个题目其实是可以用到归并的思想。为什么可以想到这个呢?
原因就在我们题目加粗的地方
我们先举例一下
举例
我们假设这两个数组是同一个数组里面分出来的,数组1在左边,数组2在右边
数组1:【1,4,6】
数组2:【3,5,9】
这个时候merge一下,我们要创建一个新的数组【0,0,0,0,0,0】
我们先比较两个数组的第一个元素,发现1比3小,
那我们根据题目,1在3的左边,那这个1是不是要被加,那这个时候我们创建一个sum
那我们这个1要被加几次呢?
是不是数组二还有多少个数就要被加几次,因为数字1在数组2的左边。
那我们比较数组1的第二个元素和数组2的第一个元素,
我们发现数组2的元素比数组1元素小,那这个时候我们只是拷贝不做其他的,这个是为什么呢?
也可以理解,因为我们左边的数字比右边大,是不用加的,
那如果两个数相同的时候,是放哪个呢?
应该先放右边的,这样才能不放过任何一个。
这样往复下来就可以了。
代码
我们先来看看merge的函数是怎么样的。
public static int merge(int[] arr , int l , int mid , int r){
int[] help = new int[r - l + 1];
int cur1 = l;
int cur2 = mid + 1;
int index = 0;
int sum = 0;
while(cur1 <= mid || cur2 <= r){
int num1 = cur1 <= mid ? arr[cur1] : Integer.MAX_VALUE;
int num2 = cur2 <= r ? arr[cur2] : Integer.MAX_VALUE;
if(num1 < num2){
sum += (num1 * (r - cur2 + 1));
help[index++] = arr[cur1++];
}else{
help[index++] = arr[cur2++];
}
}
for(int i = 0;i<help.length;i++){
arr[i + l] = help[i];
}
return sum;
}
这个函数就是这样的,需要注意的地方就是sum加等的时候,要注意计算清楚个数。其他的跟普通的merge是一样的。
之后让我们看看分割小元素的函数
public static int process(int[] arr , int l , int r){
if(l == r){
return 0;
}
int mid = l + ((r - l)/2);
int left = process(arr , l , mid);
int right = process(arr , mid + 1 , r);
int cur = merge(arr , l , mid , r);
return left +right +cur;
}
我们要知道,左边的部分和右边的部分都有返回值。cur是现在这个部分的值。
那我们最后看一下怎么调用
public static int smallSum(int[] arr){
if(arr == null || arr.length < 2){
return 0;
}
return process(arr , 0 , arr.length - 1);
}
以上就是对小和问题解答。