给你一个下标从 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^5
1 <= 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 |
|