📌  相关文章
📜  其乘积没有任何重复素因子的子数组的计数(1)

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

计算不含重复素因子的子数组个数

在这个问题中,我们需要计算给定整数数组中,乘积不含重复素因子的子数组个数。

解法

暴力方法是对于每个子数组,计算它的乘积并判断其是否含有重复素因子。这个方法需要 $O(n^2)$ 的时间复杂度,无法通过本题目。

我们可以使用类似滑动窗口的方法。假设当前考虑的子数组为 $[l, r]$,我们记 $P_l$ 为 $[l, r]$ 中所有数的乘积,若 $P_l$ 不含重复素因子,则 $[l, r]$ 一定是符合条件的子数组,我们可以令计数器 $ans$ 加一。

若 $P_l$ 含有重复素因子,则应该尝试让它变成不含重复素因子的乘积。设当前考虑到 $P_r$,我们尝试将 $l$ 不断右移,同时将 $P_l$ 除以 $a_l$,直到 $P_l$ 除以 $a_l$ 后不再含有重复素因子为止。需要使用哈希表记录每个素因子是否出现过。

使用哈希表有一个问题,那就是确定哈希表的 key 以及哈希函数。我们可以将素因子看作 key,将其对应出现的位置作为 value。在滑动窗口移动的过程中,我们可以非常简单地更新哈希表。

因为所有的素因子的值都比较小,我们可以暴力枚举素因子,选取它们为 key,时间复杂度为 $O(n \sqrt{m})$,其中 $m$ 表示所有元素的乘积。

完整算法的时间复杂度为 $O(n \sqrt{m})$,空间复杂度为 $O(\sqrt{m})$。

代码
def countSubarrays(nums: List[int]) -> int:
    def calc_pfactors(x):
        ret = set()
        for i in range(2, int(x**0.5) + 1):
            if x % i == 0:
                ret.add(i)
                while x % i == 0:
                    x //= i
        if x > 1:
            ret.add(x)
        return list(ret)

    ans = 0
    l, r = 0, 0
    pfactors = {}
    while r < len(nums):
        cur_pfactors = calc_pfactors(nums[r])
        for p in cur_pfactors:
            if p in pfactors:
                while pfactors[p] >= l:
                    pfactors[nums[l]] -= 1
                    if pfactors[nums[l]] == 0:
                        pfactors.pop(nums[l])
                    l += 1
        pfactors.update({p: r for p in cur_pfactors})
        ans += r - l + 1
        r += 1
    return ans

该算法使用 Python 语言实现。其中,calc_pfactors 函数返回 $x$ 的素因子列表。在滑动窗口移动的过程中,哈希表 pfactors 记录每个素因子最后出现的位置。若当前的乘积中含有重复素因子,则将窗口左端点右移。最后,答案即为符合条件的子数组个数。