2183. 统计可以被 K 整除的下标对数目(GCD)

217 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

每日刷题第52天 2021.02.24

1766. 互质树

题目

  • 给你一个下标从 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)
它们的积分别是 2468101220 。
其他下标对,例如 (0, 2) 和 (2, 4) 的乘积分别是 315 ,都无法被 2 整除。 
  • 示例2
输入: nums = [1,2,3,4], k = 5
输出: 0
解释: 不存在对应积可以被 5 整除的下标对。

提示

  • 1 <= nums.length <= 105
  • 1 <= nums[i], k <= 105

拓展

GCD

  • 最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。
  • 辗转相除法:模板return b == 0 ? a : Gcd(b, a % b)
  • a和b的大小无所谓,不影响。
  • 举例:a=161 b = 63,下面模拟辗转相除的执行过程
    1. a = 161 = 63 + 98, b = 63 ,那么a % b = 98, 且b != 0,因此执行Gcd(63, 98);
    2. 此时a = 63,b = 98。a < b,但是不影响,因为a % b = 63(即:63 % 98 = 63),再次执行时Gcd(98,63);程序会自动为其互换位置。
    3. a = 98 = 63 + 35,b = 63 ,那么a % b = 35,且b != 0,因此执行Gcd(63, 35);
    4. a = 63 = 35 + 28, b = 35,那么 a % b = 28,且b != 0,因此执行Gcd(35, 28);
    5. a = 35 = 28 + 7, b = 28,那么 a % b = 7,且b != 0,因此执行Gcd(28,7);
    6. a = 28 = 28 + 0, b = 7,那么 a % b = 0,且b == 0,因此执行返回b => 7;

AC代码

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */

// 最大公约
function gcd (a, b) {
    if (a % b === 0) {
        return b
    }
    return gcd(b, a % b)
}

var coutPairs = function(nums, k) {
    let count2 = 0
    const memo = new Map()

    function getCount (need) {
        if (!memo.has(need)) {
            let c = 0
            for (let i = 0; i < nums.length; i ++) {
                if ((nums[i] % need) === 0) {
                    c ++
                }
            }
            memo.set(need, c)
        }
        return memo.get(need)
    }

    for (let i = 0; i < nums.length; i ++) {
        const num = nums[i]
        const g = gcd(num, k)
        const need = k / g
        let c = getCount(need)
        if ((num % need) === 0) {
            c --
        }
        count2 += c
    }
    return count2 / 2
};

总结

  • GCD,需要掌握其原理,熟悉板子,更重要的是掌握做法