• 【891. 子序列宽度之和】


    来源:力扣(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
    • 1
    • 2
    • 3
    • 4
    • 5

    示例 2:

    输入:nums = [2]
    输出:0
    
    • 1
    • 2

    提示:

    • 1 <= nums.length <= 105
    • 1 <= nums[i] <= 105

    方法:数学

      根据子序列的定义,我们可以知道数组元素的顺序对最终结果无影响,因此我们首先对数组从小到大进行排序。对于两个元素 nums[i] 和 nums[j],其中 i < j,以 nums[i] 和 nums[j] 为最小值和最大值的子序列数目(两个元素相等时,我们以下标大小判断元素大小)为 2j−i−1 。那么所有以 nums[j] 为最大值的子序列宽度之和为(长度为 1 的子序列对结果无影响):

    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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2

    复杂度分析
    时间复杂度:O(nlog⁡n),其中 n 是数组 nums 的长度。排序需要 O(nlog⁡n),求解所有 Bj 需要 O(n)。
    空间复杂度:O(log⁡n)。排序需要 O(log⁡n) 的栈空间。
    author:力扣官方题解

  • 相关阅读:
    网络网络层之(1)IPv4地址
    短视频怎么在平台规则之内更快更好的吸引用户粉丝的关注
    Makefile三个版本的编写
    大语言模型之十七-QA-LoRA
    AmzTrends x TiDB Serverless:通过云原生改造实现全局成本降低 80%
    《开发实战》17 | 异步处理好用,但非常容易用错
    SpringMVC自定义视图解析器
    c++11知识:auto类型推导
    js中关于递归与回溯
    一些常用的数学计算方法汇总
  • 原文地址:https://blog.csdn.net/Sugar_wolf/article/details/127915981