小和问题

111 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。

题目思路

这个题目其实是可以用到归并的思想。为什么可以想到这个呢?

原因就在我们题目加粗的地方

我们先举例一下

举例

我们假设这两个数组是同一个数组里面分出来的,数组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);
}

以上就是对小和问题解答。