给你一个下标从 0 开始、长度为 n 的整数数组 nums 和一个整数 k ,返回满足下述条件的下标对 (i, j) 的数目:
0 <= i < j <= n - 1且nums[i] * nums[j]能被k整除。
示例 1:
```txt
输入: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:
```txt
输入:nums = [1,2,3,4], k = 5
输出:0
解释:不存在对应积可以被 5 整除的下标对。
```
提示:
1 <= nums.length <= 10^51 <= nums[i], k <= 10^5
统计可以被 K 整除的下标对数目
题目
给你一个下标从 0 开始、长度为 n 的整数数组 nums 和一个整数 k ,返回满足下述条件的下标对 (i, j) 的数目:
-
0 <= i < j <= n - 1且 nums[i] * nums[j]能被k整除。
示例 1:
1 | 输入:nums = [1,2,3,4,5], k = 2 |
示例 2:
1 | 输入:nums = [1,2,3,4], k = 5 |
提示:
-
1 <= nums.length <= 10^5 1 <= nums[i], k <= 10^5
题解
一个经典问题
已知正整数a,b,求正整数c,使得a*b被c整除。b一定是c/gcd(c,a)的倍数。
方法一:
思路
我们求所有nums[j](j<n)结尾的数对数量之和便是答案。
假设当前遍历到nums[j],且以j作为数对的第二关键字,那么有多少i(i<=j)作为第一关键字呢?
我们知道这样的i满足条件:nums[i]是k/gcd(nums[j],k)的倍数。
因此可以在遍历时维护哈希表cnt,cnt[i]表示i的倍数的个数。
以nums[j]结尾的数对个数有cnt[k/gcd(nums[j], k)]个,然后将nums[j]的因子在哈希表中记录。
求nums[j]的因子的时间复杂度为$O(\sqrt{nums[j]})$,总时间复杂度为$O(n^{\frac{3}{2}})$
当然我们也预处理出所有数的因子然后存储起来。
代码
1 | class Solution { |
方法二:
思路
每次我们将k/gcd(nums[j], k)记录到哈希表,以nums[j]结尾的数对个数就是哈希表中为nums[j]的因子出现次数。
代码
1 | class Solution { |
方法三:
思路
我们知道这样的i满足条件:nums[i]是k/gcd(nums[j],k)的倍数。实际上就是k因子的倍数。
在遍历时维护哈希表cnt,cnt[i]表示i的倍数的个数。
以nums[j]结尾的数对个数有cnt[k/gcd(nums[j], k)]个,然后将能除尽nums[j]的k因子在哈希表中记录。
代码
1 | class Solution { |
方法四:
思路
用哈希表统计每个数i出现的次数cnt[i]
然后类似筛选法统计i的倍数的个数times[i]。
对于nums[j],满足nums[i]*nums[j](0<=i<n)被k整除的个数有times[k/gcd(nums[j],k)]个。统计到答案中。
排除掉i!=j的nums[i],那就是满足条件:nums[j]为k/gcd(nums[j],k)]的倍数。在统计答案中减去1。
剩余情况由于任意0<=i,j<n, i!=j的nums[i]*nums[j]都一一对应nums[j]*nums[i],于是所有统计数除以2便是答案。
代码
1 |
|