LeetCode 891. 子序列宽度之和

枚举元素计算贡献

子序列,在这个题中,只关心子序列的最大值和最小值,而与子序列中数的顺序,因此可以对对数组排序后对结果不产生影响。

排完序之后可以看到对于一个数nums[i]来说,如果所在的子序列中它是最大的,那么它对结果的贡献就为正的+nums[i]。如果它在子序列中它为最小的,那么它对结果的贡献为负的即-nums[i]
接下来问题就变成了寻找nums[i]在多少个子序列中为最大值,在多少个子序列中为最小值。
排完序之后(升序),我们可以发现,当nums[i]与只其前面的数和自身组成子序列时,nums[i]在所组成的子序列中为最大值,通过数学公式我们可以知道此时以nums[i]为最大值的子序列个数为 2 i 2^i 2i。同理当nums[i]只与自身和其后边数组成子序列时,所组成的子序列nums[i]为最小值,有 2 n − 1 − 1 2^{n - 1 - 1} 2n11

因此nums[i]对结果的贡献为 ( 2 i − 2 n − 1 − i ) ∗ n u m s [ i ] (2^i - 2^{n - 1 - i}) * nums[i] (2i2n1i)nums[i],将所有元素的贡献求和,即可得到结果。

这个题还有一个需要注意的地方就是在计算2的指数时可能会溢出,因此也需要对2的指数进行模运算。这里可以用一个数组保存2指数运算的结果

class Solution {
public:
    int sumSubseqWidths(vector<int>& nums) {
        long long MOD = 1e9 + 7;
        int n = nums.size();
        int pow2[n];
        pow2[0] = 1;
        for(int i = 1; i < n; i++)
            pow2[i] = (pow2[i - 1] * 2) % MOD;
        int res = 0;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < n; i++)
        {
            res = (res + long(pow2[i] - pow2[n - 1 - i]) * nums[i]) % MOD;
        }
        return (res + MOD) % MOD;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值