Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
每日刷题第52天 2021.02.24
1766. 互质树
- leetcode原题链接:leetcode-cn.com/problems/tr…
- 难度:困难
- 方法:二分查找
题目
- 给你一个下标从 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 <= 1051 <= nums[i], k <= 105
拓展
GCD
- 最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。
- 辗转相除法:模板
return b == 0 ? a : Gcd(b, a % b) - a和b的大小无所谓,不影响。
- 举例:
a=161 b = 63,下面模拟辗转相除的执行过程a = 161 = 63 + 98, b = 63,那么a % b = 98, 且b != 0,因此执行Gcd(63, 98);- 此时
a = 63,b = 98。a < b,但是不影响,因为a % b = 63(即:63 % 98 = 63),再次执行时Gcd(98,63);程序会自动为其互换位置。 a = 98 = 63 + 35,b = 63,那么a % b = 35,且b != 0,因此执行Gcd(63, 35);a = 63 = 35 + 28, b = 35,那么a % b = 28,且b != 0,因此执行Gcd(35, 28);a = 35 = 28 + 7, b = 28,那么a % b = 7,且b != 0,因此执行Gcd(28,7);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,需要掌握其原理,熟悉板子,更重要的是掌握做法