图解LeetCode——891. 子序列宽度之和(难度:困难)

一、题目

一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。

给你一个整数数组 nums ,返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大,请返回对 10^9 + 7 取余 后的结果。

子序列 定义为从一个数组里删除一些(或者不删除)元素,但不改变剩下元素的顺序得到的数组。例如,[3,6,2,7] 就是数组 [0,3,1,6,2,2,7] 的一个子序列。

二、示例

2.1> 示例 1:

【输入】nums = [2,1,3]
【输出】6
【解释】子序列为 [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3] 。相应的宽度是 0, 0, 0, 1, 1, 2, 2 。宽度之和是 6 。

2.2> 示例 2:

【输入】nums = [2]
【输出】0

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

三、解题思路

根据题目描述我们可以知道,计算宽度的时候,只是需要计算序列中【最大元素】与【最小元素】的差值。那么我们只需要关心数组nums中数字的大小而不需要关心它所在的位置了,即:子序列[2,4]与子序列[4,2]差值都是2。

那么,既然我们主要关注点是数组nums中的每个元素值大小,为了方便计算,我们首先可以对nums进行排序操作。

排序之后,我们随便找一个下标为i的元素,可以找到以下规律:

 下面是以nums[i]其左侧所有元素拼装组合成的子序列示例:

 那么,针对于nums[i]来说,它的宽度总和就是: (2^i-2^(nums.length-i-1)) * nums[i] ,那么我们遍历所有nums数组中的元素,逐一计算每个元素的宽度总和,那么最终结果就是本题的答案。

四、代码实现

class Solution {
    public int sumSubseqWidths(int[] nums) {
        Arrays.sort(nums); // 排序
        int mod = (int)1e9 + 7, n = nums.length;
        long result = 0;
        long[] pow = new long[n];
        pow[0] = 1;
        for (int i = 1; i < n; i++) 
            pow[i] = (pow[i - 1] << 1) % mod; // 初始化2^n的值

        for (int i = 0; i < n; i++)
            result = (result + (pow[i] - pow[n-i-1]) * nums[i] % mod) % mod; // 计算总和          
        return (int)result;
    }
}

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值