LC 891. 子序列宽度之和 (opens new window) (opens new window)
困难
# 问题描述
一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。
给你一个整数数组 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
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 105
# 数学
对于一个子序列,决定该子序列宽度的主要因素为序列的最大值与最小值,与序列中元素的顺序无关,因此可以对原数组进行排序。排序后,对于某个数 ,它有两种情况: 为最大值以及 为最小值。
- 当 为最小值时,大于等于 的元素个数有 个,能够组成的子序列的个数即为 ,贡献值为
- 当 为最大值时,小于等于 的元素个数有 个,能够组成的子序列的个数即为 ,贡献值为
计算所有 作为最大值时的贡献值之和与作为最小值时的贡献值之和,他们的差值即为所有非空子序列的宽度之和。
/**
* @param {number[]} nums
* @return {number}
*/
var sumSubseqWidths = function (nums) {
const MOD = 10 ** 9 + 7
const n = nums.length
nums.sort((a, b) => a - b)
const pow = new Array(n).fill(1)
// 预处理 2^n
for (let i = 1; i < n; i++) {
pow[i] = (pow[i - 1] * 2) % MOD
}
let ans = 0
for (let i = 0; i < n; i++) {
ans = (ans + nums[i] * (pow[i] - pow[n - i - 1])) % MOD
}
return ans
}
- 时间复杂度:
- 空间复杂度:
上次更新: 2023/01/31 19:48:05
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 , 转载请注明出处!