一、题目
一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。
给你一个整数数组 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^)/ ~ 「干货分享,每天更新」