Skip to content

Latest commit

 

History

History

0891.Sum of Subsequence Widths

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

English Version

题目描述

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

给你一个整数数组 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 中所有子序列中最大值与最小值差值之和,注意到“子序列”,并且涉及到“最大值”与“最小值”,我们考虑先对数组 nums 进行排序。

然后我们枚举数组 nums 中的每个元素 $nums[i]$,该元素左侧的元素个数为 $i$,右侧的元素个数为 $n-i-1$

如果我们将元素 $nums[i]$ 作为子序列的最大值,总共有多少个满足条件的子序列呢?显然,子序列的其他元素应该从左侧的 $i$ 个元素中选取,每个元素有两种选择,即选或不选,因此总共有 $2^i$ 个子序列。同理,如果我们将元素 $nums[i]$ 作为子序列的最小值,那么总共有 $2^{n-i-1}$ 个满足条件的子序列。因此 $nums[i]$ 对答案的贡献为:

$$ \begin{aligned} nums[i] \times (2^i - 2^{n-i-1}) \end{aligned} $$

我们将数组 nums 中所有元素的贡献累加,即为答案:

$$ \begin{aligned} \sum_{i=0}^{n-1} nums[i] \times (2^i - 2^{n-i-1}) \end{aligned} $$

我们将上式展开,可以得到:

$$ \begin{aligned} nums[0] \times (2^0 - 2^{n-1}) + nums[1] \times (2^1 - 2^{n-2}) + ... + nums[n-1] \times (2^{n-1} - 2^0) \end{aligned} $$

再将式子中相同的幂次项合并,可以得到:

$$ \begin{aligned} (nums[0] - nums[n-1]) \times 2^0 + (nums[1] - nums[n-2]) \times 2^1 + ... + (nums[n-1] - nums[0]) \times 2^{n-1} \end{aligned} $$

即:

$$ \begin{aligned} \sum_{i=0}^{n-1} (nums[i] - nums[n-i-1]) \times 2^i \end{aligned} $$

因此我们只需要对数组 nums 进行排序,然后计算上述的贡献即可。注意答案的取模操作。

时间复杂度 $O(n\times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为数组 nums 的长度。

Python3

class Solution:
    def sumSubseqWidths(self, nums: List[int]) -> int:
        mod = 10**9 + 7
        nums.sort()
        ans, p = 0, 1
        for i, v in enumerate(nums):
            ans = (ans + (v - nums[-i - 1]) * p) % mod
            p = (p << 1) % mod
        return ans

Java

class Solution {
    private static final int MOD = (int) 1e9 + 7;

    public int sumSubseqWidths(int[] nums) {
        Arrays.sort(nums);
        long ans = 0, p = 1;
        int n = nums.length;
        for (int i = 0; i < n; ++i) {
            ans = (ans + (nums[i] - nums[n - i - 1]) * p + MOD) % MOD;
            p = (p << 1) % MOD;
        }
        return (int) ans;
    }
}

C++

class Solution {
public:
    const int mod = 1e9 + 7;

    int sumSubseqWidths(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        long ans = 0, p = 1;
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            ans = (ans + (nums[i] - nums[n - i - 1]) * p + mod) % mod;
            p = (p << 1) % mod;
        }
        return ans;
    }
};

Go

func sumSubseqWidths(nums []int) (ans int) {
	const mod int = 1e9 + 7
	sort.Ints(nums)
	p, n := 1, len(nums)
	for i, v := range nums {
		ans = (ans + (v-nums[n-i-1])*p + mod) % mod
		p = (p << 1) % mod
	}
	return
}

...