力扣第891题——子序列宽度之和

本文介绍了一种求解整数数组所有非空子序列宽度之和的有效算法,并提供了两种解决方案,一种是直观的双重循环方法,另一种是针对大数据输入进行了优化的高效实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题是前天的每日一题,题目如下:

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

给你一个整数数组 nums ,返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大,请返回对 109 + 7 取余 后的结果。

子序列 定义为从一个数组里删除一些(或者不删除)元素,但不改变剩下元素的顺序得到的数组。例如,[3,6,2,7] 就是数组 [0,3,1,6,2,2,7] 的一个子序列。

解题思路

由题意可知,这道题是让求子序列最大值最小值的差值。由于子序列可以不连续,且本题只需要关注两个最值,因此给的数组的顺序也就并不重要了,就是说数组的顺序对题的答案并不会产生影响。所以我们可以对数组进行排序,如此一来就方便我们找最大值和最小值了。

nums.sort((a, b) => a - b);//对数组进行排序

排完序后,我们就可以开始计算宽度了,设两个数分别为最大值和最小值,那么这一组最大值最小值对应的所有子序列的宽度之和,等于这两个数的差值乘上排完序后两数之间数的个数的组合的数量。

所以,我们可以这样写

var sumSubseqWidths = function(nums) {
    nums.sort((a, b) => a - b);
    let sum = 0;
    for(let i = 0;i<nums.length;i++){
        for(let j=i+1;j<nums.length;j++){
            let mul = Math.pow(2,j-i-1)% 1000000007;
            sum = (sum + (nums[j]-nums[i])*mul% 1000000007) % 1000000007;
        }
    }
    return sum;
};

这样写逻辑上没有毛病,在遇到一些不是那么长数据不是那么奇怪的案例的时候,都是能通过的。但是遇到那些特别长的案例,就需要用数学的方法优化一下了。

var sumSubseqWidths = function(nums) {
    nums.sort((a, b) => a - b);
    let sum = 0;
    let x = nums[0], y = 2;
    for (let j = 1; j < nums.length; j++) {
        sum = (sum + nums[j] * (y - 1) - x) % 1000000007;
        x = (x * 2 + nums[j]) % 1000000007;
        y = y * 2 % 1000000007;
    }
    return sum;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值