来源:力扣(LeetCode)
描述:
一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。
给你一个整数数组 nums ,返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大,请返回对 109 + 7 取余 后的结果。
子序列 定义为从一个数组里删除一些(或者不删除)元素,但不改变剩下元素的顺序得到的数组。例如,[3,6,2,7] 就是数组 [0,3,1,6,2,2,7] 的一个子序列。
示例 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:
输入:nums = [2]
输出:0
提示:
方法:数学
根据子序列的定义,我们可以知道数组元素的顺序对最终结果无影响,因此我们首先对数组从小到大进行排序。对于两个元素 nums[i] 和 nums[j],其中 i < j,以 nums[i] 和 nums[j] 为最小值和最大值的子序列数目(两个元素相等时,我们以下标大小判断元素大小)为 2j−i−1 。那么所有以 nums[j] 为最大值的子序列宽度之和为(长度为 1 的子序列对结果无影响):
因此 Bj+1 的结果可以利用计算 Bj 时的部分数据来计算,记 yj = 2j,那么 Bj = nums[j] × (yj − 1) − xj, Bj+1 = nums[j+1] × (yj+1 − 1) − xj ,由上面的推导可知 yj+1 = 2 × yj,xj+1 = 2 × xj + nums[j]。所有子序列的宽度之和就是所有 Bj 的和。
代码:
class Solution {
public:
int sumSubseqWidths(vector<int>& nums) {
sort(nums.begin(), nums.end());
long long res = 0, mod = 1e9 + 7;
long long x = nums[0], y = 2;
for (int j = 1; j < nums.size(); j++) {
res = (res + nums[j] * (y - 1) - x) % mod;
x = (x * 2 + nums[j]) % mod;
y = y * 2 % mod;
}
return (res + mod) % mod;
}
};
复杂度分析
时间复杂度:O(nlogn),其中 n 是数组 nums 的长度。排序需要 O(nlogn),求解所有 Bj 需要 O(n)。
空间复杂度:O(logn)。排序需要 O(logn) 的栈空间。
author:力扣官方题解