【力扣每日一题 0801】LEETCODE 2681. 英雄的力量

题目

LEETCODE 2681
简单来说,就是定义力量值为若干个整数中最大值的平方乘以最小值,然后给一个整数数组,要求算出其中所有的非空组合的力量值的和,结果需要取模。

算法描述

首先分析一下,这种题目的套路通常是算“贡献”,即分开进行计数统计。
然后不难发现与顺序无关,所以按从小到大排序后,以每个数作为组合中的最大值的贡献入手,只需要求出小于等于当前数的数字中,所有包含当前数的组合的最小值之和,再乘以当前数的平方,即为贡献,最后将各个贡献相加即可求得答案。
分析到这里,关键问题在于如何求小于等于当前数的数字中所有包含当前数的组合的最小值之和。由于排过序了,更简便且精确的表述是前 i i i个数的所有包含 i i i个数的组合的最小值之和。不难想到用递推/动态规划的思想去考虑。记给定的已排序的数组为 a a a,设 f ( i ) f(i) f(i)表示前 i i i个数中所有非空组合(不一定包含 i i i个数)的最小值之和,那么 f ( 0 ) = 0 f(0)=0 f(0)=0 f ( 1 ) = a [ 1 ] f(1)=a[1] f(1)=a[1],再分析一下递推关系,组合中不包含 a [ i ] a[i] a[i]的话结果为 f ( i − 1 ) f(i-1) f(i1),包含 a [ i ] a[i] a[i]的话,考虑一下非空组合的问题,结果应为 f ( i − 1 ) + a [ i ] f(i-1)+a[i] f(i1)+a[i],综上,递推公式如下:
f ( i ) = 2 × f ( i − 1 ) + a [ i ] f(i) = 2 \times f(i-1)+a[i] f(i)=2×f(i1)+a[i]
而我们关心的是前 i i i个数的所有包含 i i i个数的组合的最小值之和,这通过 f ( i ) f(i) f(i)并不难求,即 f ( i − 1 ) + a [ i ] f(i-1)+a[i] f(i1)+a[i]
所以,第 i i i个数作为组合中的最大值产生的贡献即为 a [ i ] 2 × ( f ( i − 1 ) + a [ i ] ) a[i]^{2} \times (f(i-1)+a[i]) a[i]2×(f(i1)+a[i]),累加即可得答案。

分析一下复杂度:
时间复杂度:递推是 O ( n ) O(n) O(n)的,但是排序是 O ( n l o g n ) O(nlogn) O(nlogn)的,所以时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度:后面的递推可以使用滚动数组,空间可以优化到常数级,但是排序需要用到 O ( l o g n ) O(logn) O(logn)的递归调用栈空间。

需要注意一下,写法上的细节问题,如位运算、滚动数组、取模等,参照代码实现。

代码实现

typedef long long ll;
const ll P = 1e9 + 7;
class Solution {
public:
    int sumOfPower(vector<int>& nums) {
        int n = nums.size();
        vector<ll> f;
        f.resize(2);
        int ans = 0;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < n; i++) {
            int ii = (i&1);
            f[ii] = (f[ii^1] << 1) % P;
            f[ii] = (f[ii] + nums[i]) % P;
            ll tmp = 1LL * nums[i] * nums[i] % P;
            ll tmp1 = (f[ii^1] + nums[i]) % P;
            tmp = tmp * tmp1 % P;
            ans = ((ll)ans + tmp) % P;
        }
        return ans;
    }
};

关键词

力扣 每日一题 英雄的力量 2681 动态规划 前缀和 递推

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值