Leetcode.2862 完全子集的最大元素和

题目链接

Leetcode.2862 完全子集的最大元素和 rating : 2292

题目描述

给你一个下标从 1 1 1 开始、由 n n n 个整数组成的数组。你需要从 n u m s nums nums 选择一个 完全集,其中每对元素下标的乘积都是一个 完全平方数,例如选择 a i a_i ai a j a_j aj i ∗ j i * j ij 一定是完全平方数。

返回 完全子集 所能取到的 最大元素和

示例1:
输入:nums = [8,7,3,5,7,2,4,9]
输出:16
解释:
我们选择下标为 2 和 8 的元素,并且 1 * 4 是一个完全平方数。
示例2:
输入:nums = [8,10,3,8,1,13,7,9,4]
输出:20
解释:
我们选择下标为 1, 4, 9 的元素。1 * 4, 1 * 9, 4 * 9 是完全平方数。
提示:
  • 1 ≤ n = n u m s . l e n g t h ≤ 1 0 4 1 \leq n = nums.length \leq 10^4 1n=nums.length104
  • 1 ≤ n u m s [ i ] ≤ 1 0 9 1 \leq nums[i] \leq 10^9 1nums[i]109

解法:质因数分解 + 数学

如果 i ∗ j i * j ij 是一个 完全平方数,那么 i f i × j f j \frac{i}{f_i} \times \frac{j}{f_j} fii×fjj 也是一个完全平方数。( f i , f j f_i,f_j fi,fj 分别是 i , j i,j i,j最大平方因子,即 f i , f j f_i,f_j fi,fj 也是完全平方数)。

证明过程:
如果一个数是完全平方数,那么它的每一个质因子都应该是偶数个。

因为 i ∗ j i * j ij 是完全平方数。 i ∗ j = f i ∗ i f i ∗ f j ∗ j f j i * j =f_i * \frac{i}{f_i} *f_j* \frac{j}{f_j} ij=fifiifjfjj

因为 f i , f j f_i,f_j fi,fj 也是完全平方数,所以 i f i × j f j \frac{i}{f_i} \times \frac{j}{f_j} fii×fjj 剩余的因子都应该是 偶数个,即 i f i × j f j \frac{i}{f_i} \times \frac{j}{f_j} fii×fjj 也是一个完全平方数。

举例: 2 × 18 2 \times 18 2×18 是一个完全平方数, 2 2 2 的最大平方因子为 1 1 1 18 18 18 的最大平方因子是 9 9 9 2 1 × 18 9 = 2 × 2 = 4 \frac{2}{1} \times \frac{18}{9} = 2 \times 2 = 4 12×918=2×2=4 依旧是一个完全平方数。

两个数 i , j i,j i,j,如果 i f i = j f j \frac{i}{f_i} = \frac{j}{f_j} fii=fjj,那么 i ∗ j i *j ij 就是一个完全平方数。

所以在进行 质因数分解,获取最大平方因子 f i f_i fi时,我们以 i f i \frac{i}{f_i} fii 分组,同一组内元素两两相乘都是完全平方数。直接遍历获取最大的和返回即可。

时间复杂度: O ( n × l o g n ) O(n\times logn) O(n×logn)

C++代码:

using LL = long long;

class Solution {
public:
    long long maximumSum(vector<int>& nums) {
        int n = nums.size();
        unordered_map<int,LL> cnt;

        for(int i = 1;i <= n;i++)
        {
            auto x = i;
            int f = 1;

            for(int d = 2;d <= x / d;d++)
            {
                if(x % d == 0)
                {
                    int k = 0, s = 1;
                while(x % d == 0)
                {
                    x /= d;
                    s *= d;
                    k++;
                }
                //如果k是奇数 需要去掉一个
                //比如 s = 2 * 2 * 2, 由于我们是要求最大平方因子, 所以只需要偶数个, 即 2 * 2 
                if(k & 1) s /= d;
                f *= s;
                }
            }
            //按 i / fi 分组记录记录元素和
            cnt[i / f] += nums[i - 1];
        }

        LL ans = 0;
        for(auto [k, v]:cnt)
        {
            ans = max(ans, v);
        }

        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值