C++ 程序设计:统计可以被 K 整除的下标对数目(LeetCode:2183)

给你一个下标从 0 开始、长度为 n 的整数数组 nums 和一个整数 k ,返回满足下述条件的下标对 (i, j) 的数目:

0 <= i < j <= n - 1 且
nums[i] * nums[j] 能被 k 整除。
 

示例 1:

输入:nums = [1,2,3,4,5], k = 2
输出:7
解释:
共有 7 对下标的对应积可以被 2 整除:
(0, 1)、(0, 3)、(1, 2)、(1, 3)、(1, 4)、(2, 3) 和 (3, 4)
它们的积分别是 2、4、6、8、10、12 和 20 。
其他下标对,例如 (0, 2) 和 (2, 4) 的乘积分别是 3 和 15 ,都无法被 2 整除。    
示例 2:

输入:nums = [1,2,3,4], k = 5
输出:0
解释:不存在对应积可以被 5 整除的下标对。
 

提示:

1 <= nums.length <= 10^5
1 <= nums[i], k <= 10^5

思路:比较直观的做法是采用两层for循环枚举对数,但O(n^2)的复杂度必然造成超时。考虑能够整除k的数满足的性质,当x可以整除k时,则x的因数必包含k的所有因数,即:

gcd(x, k) = k (gcd为最大公因数)

从中可以发现nums[i]*nums[j]%k=0可以转化为找到两个元素nums[i]和nums[j]使得:

gcd(nums[i], k) * gcd(nums[j], k) = 0

我们令gcd(nums[i], k) 为x,gcd(nums[j], k) 为y:

因此我们只需事先求出所有元素与k的最大公因数,并统计出现的次数,之后借助map以双层for遍历x和y 即可。由于x和y为k的因数,因此两层for循环的复杂度为O(k),而总的时间复杂度为O(nlogn + k)。

class Solution {
public:
    int gcd(int a, int b) {
        if (b == 0)
            return a;
        return gcd(b, a % b);
    }
    long long countPairs(vector<int>& nums, int k) {
        unordered_map<int, int> sum;
        for (int num : nums)
            ++sum[gcd(num, k)];
        long long ans = 0;
        for (auto&& [x, sumX] : sum)
            for (auto&& [y, sumY] : sum)
                if (static_cast<long long>(x) * y % k == 0)
                    ans += static_cast<long long>(sumX) * sumY;
        for (int num : nums)
            if (static_cast<long long>(num) * num % k == 0)
                --ans;
        return ans / 2;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值