目录

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

# 数学

对于一个子序列,决定该子序列宽度的主要因素为序列的最大值与最小值,与序列中元素的顺序无关,因此可以对原数组进行排序。排序后,对于某个数 nums[i]nums[i],它有两种情况:nums[i]nums[i] 为最大值以及 nums[i]nums[i] 为最小值。

  • nums[i]nums[i] 为最小值时,大于等于 nums[i]nums[i] 的元素个数有 ni1n - i - 1 个,能够组成的子序列的个数即为 2ni12^{n-i-1},贡献值为 nums[i]×2ni1nums[i] \times 2^{n-i-1}
  • nums[i]nums[i] 为最大值时,小于等于 nums[i]nums[i] 的元素个数有 ii 个,能够组成的子序列的个数即为 2i2^i,贡献值为 nums[i]×2inums[i] \times 2^i

计算所有 nums[i]nums[i] 作为最大值时的贡献值之和与作为最小值时的贡献值之和,他们的差值即为所有非空子序列的宽度之和。

/**
 * @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
}
  • 时间复杂度:O(nlogn)O(n\log{n})
  • 空间复杂度:O(n)O(n)
上次更新: 2023/01/31 19:48:05

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 , 转载请注明出处!