常见算法之求最小和(4)

给定一个数组,求出数组每个位置的数的左边比它小的值之和。

比如给定数组【1,3,4,2,5】;

1的左边小于1的没有;

3左边小于3的为1;

4左边小于4的为1、3;

2左边小于2的为1;

5左边小于5的为1、3、4、2;

最后求和得到值为16。

下面直接上最优解

求左侧比它小的数的和,等同于求右侧比它大的数的个数 * 其值

1的右侧比它大的有4个 * 1 +

3的右侧比它大的有2个 * 3 +

4的右侧比它大的有1个 * 4 +

2的右侧比它大的有1个 * 2 +

5的右侧比它大的有0个 * 5

= 16

代码实现如下:

    public static int minSum(int[] data, int l, int r) {
        if (l == r) {
            return 0;
        }
        //求中间坐标
        int m = l + (r - l >> 1);
        return minSum(data, l, m) +
                minSum(data, m + 1, r) +
                mergerMinSum(data, l, r, m);
    }
    
private static int mergerMinSum(int[] data, int l, int r, int m) {
        int[] temp = new int[r - l + 1];
        int i = 0;
        int p1 = l, p2 = m + 1, sum = 0;
        while (p1 <= m && p2 <= r) {
            //右侧比它大的数的个数 * 它本身之和
            sum += data[p1] < data[p2] ? data[p1] * (r - p2 + 1) : 0;
            temp[i++] = data[p1] < data[p2] ? data[p1++] : data[p2++];
        }
        while (p1 <= m) {
            temp[i++] = data[p1++];
        }
        while (p2 <= r) {
            temp[i++] = data[p2++];
        }
        // l左边为已经排序好的数组
        int length = temp.length;
        for (int j = 0; j < length; j++) {
            data[l + j] = temp[j];
        }
        return sum;
    }

类似归并排序,将数组分为左右两部分,然后merger求和。

在merger求和的过程中,左边和右边的比较,如果左边小于则sum+= 值* 右边数的个数;然后将小的那边拷贝到数组。为啥是拷贝小的到临时数组中呢?因为小的已经计算过一遍了,需要到到比较的左右子数组之外。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知始行末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值