当前位置: 首页 > news >正文

LeetCode 2176. 统计数组中相等且可以被整除的数对

给你一个下标从 0 开始长度为 n 的整数数组 nums 和一个整数 k ,请你返回满足 0 <= i < j < n ,nums[i] == nums[j] 且 (i * j) 能被 k 整除的数对 (i, j) 的 数目 。

示例 1:

输入:nums = [3,1,2,2,2,1,3], k = 2
输出:4
解释:
总共有 4 对数符合所有要求:

  • nums[0] == nums[6] 且 0 * 6 == 0 ,能被 2 整除。
  • nums[2] == nums[3] 且 2 * 3 == 6 ,能被 2 整除。
  • nums[2] == nums[4] 且 2 * 4 == 8 ,能被 2 整除。
  • nums[3] == nums[4] 且 3 * 4 == 12 ,能被 2 整除。

1 <= nums.length <= 100
1 <= nums[i], k <= 100

解法一:直接模拟题意:

class Solution {
public:
    int countPairs(vector<int>& nums, int k) {
        int ans = 0;
        for (int i = 0; i < nums.size(); ++i) {
            for (int j = i + 1; j < nums.size(); ++j) {
                if ((nums[i] == nums[j]) && ((i * j) % k == 0)) {
                    ++ans;
                }
            }
        }

        return ans;
    }
};

如果输出数组nums的长度为n,此算法时间复杂度O(n 2 ^2 2),空间复杂度O(1)。

解法二:如果(i * j) % k == 0,有:
i = g c d ( i , k ) i g c d ( i , k ) i = gcd(i,k)\frac{i}{gcd(i,k)} i=gcd(i,k)gcd(i,k)i

i ∗ j = g c d ( i , k ) i g c d ( i , k ) j = q k ( q 为整数) i*j=gcd(i,k)\frac{i}{gcd(i,k)}j=qk(q为整数) ij=gcd(i,k)gcd(i,k)ij=qkq为整数)
两端同时除gcd(i,k)可得:
i g c d ( i , k ) j = q k g c d ( i , k ) \frac{i}{gcd(i,k)}j=\frac{qk}{gcd(i,k)} gcd(i,k)ij=gcd(i,k)qk
又由于以下两式互质:
( i g c d ( i , k ) , k g c d ( i , k ) ) = 1 (\frac{i}{gcd(i,k)} , \frac{k}{gcd(i,k)})=1 (gcd(i,k)i,gcd(i,k)k)=1
因此:
j = p k g c d ( i , k ) ( p 为整数) j = \frac{pk}{gcd(i,k)}(p为整数) j=gcd(i,k)pkp为整数)
即我们只需要遍历所有下标,对于每个下标i,找到i和k的最大公因数,然后用k除该最大公因数得到g,j就是g的倍数了,然后再看满足nums[i]和nums[j]的个数即符合题意的数对,我们可以先遍历一遍数组,找出每个g的整数倍下标对应的元素值及其个数,遍历时直接加即可:

class Solution {
public:
    int countPairs(vector<int>& nums, int k) {
        unordered_map<int, unordered_map<int, int>> factorAndNum;

        int maxFactor = nums.size();
        if (k + 1 < maxFactor) {
            maxFactor = k + 1;
        }
        // 第二层循环为调和级数级时间复杂度O(lgn),此处两层循环时间复杂度为O(nlgn)
        for (int i = 1; i < maxFactor; ++i) {
            for (int j = i; j < nums.size(); j += i) {
                ++factorAndNum[i][nums[j]];
            }
        }

        int ans = 0;
        for (int i = 0; i < nums.size(); ++i) {
            int factor = k / gcd(i, k);
            
            ans += factorAndNum[factor][nums[i]];
            // 此处需特殊处理0,因为上面预处理时按下标的倍数计算,0的任何倍数都是0
            if (nums[i] == nums[0]) {
                ++ans;
            }
			// 去掉i本身,如果i也是factor的倍数,说明被多计算了一次
            if (i % factor == 0) {
                --ans;
            }
        }
    	// 最后结果需要除2,因为nums[i]==nums[j]时,遍历到i和j分别计算了两次
        return ans / 2;
    }
};

如果输入数组长度为n,此算法时间复杂度为O(nlgn),空间复杂度为(nlgn)。

以上过程中,有一个结论:两个数分别除以这两数的最大公因数,所得的商互质。因为每个数都可以写成若干质数的乘积,最大公因数是取出两个质数池中的公共部分,两个集合中剩下的因数一定互质。如36=2233,24=2223,最大公因数为223=12,剩下的数分别为2和3,是互质的。

相关文章:

  • 直线生成算法(DDA算法)
  • 10技术太卷我学APEX-导航卡Card
  • 红黑树插入结点
  • python入门 之 字典(六)
  • 通过python编写自定义尺寸和位置批量进行图像剪裁
  • 开发人员对需求的正确打开方式
  • SQLSERVER 快照隔离级别 到底怎么理解?
  • 《SQL基础》09. 事务
  • 设计模式-第1章(简单工厂模式)
  • springboot,vue教务管理系统
  • 5.6 频率响应与阶跃响应
  • Next.js 中的 SEO
  • 初识Linux基础工具之yum vim gcc gdb git以及简单makefile文件的编写
  • Traffic Signs Recognition with 95% Accuracy using CNNKeras
  • axios中params和data的区别
  • 【QT】C++和QML使用多线程优化界面切换卡顿的方法
  • kob后端1
  • Kotlin~工厂方法、抽象工厂模式
  • C++继承(下)
  • PKI证书签发系统(2.0web版)
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉