📜  计算 Array 中乘积为任意正整数的 K 次方的对(1)

📅  最后修改于: 2023-12-03 15:27:57.790000             🧑  作者: Mango

题目

计算 Array 中乘积为任意正整数的 K 次方的对

问题描述

给定一个长度为 $n$ 的整数数组 $nums$ 和一个整数 $k$,请问你需要找出有多少对不同的索引 $(i, j)$,使得 $nums_i \times nums_j = t^k$,其中 $t$ 是一个任意正整数。

解题思路

首先,我们遍历数组 $nums$,对数组中的每个元素 $num_i$,我们都计算出其因数分解后的因数集合 $factors_i$。这部分的时间复杂度为 $O(n \sqrt{max(nums_i)})$。

对于每一对数 $(i, j)$,我们需要计算 $nums_i$ 和 $nums_j$ 所对应的因数集合的交集。如果其交集中每个元素都恰好出现了 $k$ 次,那么这一对数就可以被计入答案中。

这里利用一个技巧:我们可以对于所有的因数 $x$,用一个数组 $cnt_x$ 记录其出现次数。对于数 $num_i$ 所对应的因数集合 $factors_i$ 中的每个因数 $x$,我们就可以让 $cnt_x$ 自增一。接着,我们再对于数 $num_j$ 所对应的因数集合 $factors_j$ 中的每个因数 $x$,我们就可以让 $cnt_x$ 再次自增一。这样在遍历所有的因数后,我们只需要看一看 $cnt_x$ 中每个值是否都为 $2k$,如果是的话,那么 $(i, j)$ 这一组乘积为 $t^k$,可以被计入答案中。

这里也有一些优化技巧:我们可以在记录 $cnt_x$ 的时候,直接跳过所有大于 $\sqrt{max(nums_i)}$ 的因数,因为这些因数显然不会出现在数组 $nums$ 的因数集合中。

时间复杂度分析:我们至多需要遍历数组 $nums$ $n$ 次,对于每个元素都需要进行一次因数分解,时间复杂度为 $O(n \sqrt{max(nums_i)})$。同时,对于每一组 $(i, j)$,判断它们所对应的因数集合的交集中是否满足条件只需要 $O(\sqrt{max(nums_i)})$ 的时间。因此,该算法的总时间复杂度为 $O(n^2 \sqrt{max(nums_i)})$。

代码实现

from collections import defaultdict
from typing import List

class Solution:
    def getFactors(self, num: int) -> List[int]:
        factors = []
        i = 2
        while i * i <= num:
            if num % i == 0:
                factors.append(i)
                num //= i
                i = 2
            else:
                i += 1
        if num != 1:
            factors.append(num)
        return factors

    def calcMultiplicationPairs(self, nums: List[int], k: int) -> int:
        n = len(nums)
        cnt = defaultdict(int)
        ans = 0
        for i in range(n):
            factors_i = self.getFactors(nums[i])
            for factor in factors_i:
                if factor * factor <= nums[i]:
                    cnt[factor] += 1
                if nums[i] // factor != factor:
                    if nums[i] // factor <= max(nums):
                        cnt[nums[i] // factor] += 1
            for j in range(i + 1, n):
                flag = True
                factors_j = self.getFactors(nums[j])
                for factor in factors_j:
                    if factor * factor <= nums[j]:
                        cnt[factor] += 1
                        if cnt[factor] % k:
                            flag = False
                    if nums[j] // factor != factor:
                        if nums[j] // factor <= max(nums):
                            cnt[nums[j] // factor] += 1
                            if cnt[nums[j] // factor] % k:
                                flag = False
                if flag:
                    ans += 1
                for factor in factors_j:
                    if factor * factor <= nums[j]:
                        cnt[factor] -= 1
                    if nums[j] // factor != factor:
                        if nums[j] // factor <= max(nums):
                            cnt[nums[j] // factor] -= 1
        return ans

注:此代码由机器人撰写,仅供参考。