📜  计数长度为K的数组,其元素乘积与给定数组的乘积相同(1)

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

问题描述

给定一个长度为 n 的整数数组 nums 和一个整数 k,计算有多少个长度为 k 的子数组具有相同的乘积,使得这个乘积等于原数组 nums 中所有元素的乘积。

解法思路

思路1 - 暴力枚举

由于子数组的长度已经给出,因此可以对每个长度为 k 的子数组的元素进行乘积的计算,并将其与原数组 nums 所有元素的乘积进行比较。

时间复杂度:$O(nk)$

思路2 - 哈希表

对于数组 nums 内每个元素进行质因数分解,并将每个元素的所有质数因子及其指数添加至哈希表 factor 中。

对于长度为 k 的子数组,同样进行质因数分解,并将其中包含的质数因子及其指数添加至哈希表 temp 中,并将其作为某个因子集合。

如果哈希表 temp 中所包含的因子集合在 factor 中也存在,则将相应的数量进行相加即可。

时间复杂度:$O(nk)$

代码实现

暴力枚举
def countSubarrays(nums: List[int], k: int) -> int:
    n = len(nums)
    ans = 0
    p = 1
    for i in range(n - k + 1):
        if i == 0:
            for j in range(k):
                p *= nums[j]
        else:
            p = p // nums[i - 1] * nums[i + k - 1]
        for j in range(k):
            if p == nums[i] * nums[i + 1] * ... nums[i + k - 1]:
                ans += 1
    return ans
哈希表
def countSubarrays(nums: List[int], k: int) -> int:
    # 获取因子列表
    def getFactor(x: int) -> List[Tuple[int, int]]:
        factor = []
        up_bd = int(x ** 0.5)
        for i in range(2, up_bd + 1):
            if x % i == 0:
                cnt = 0
                while x % i == 0:
                    cnt += 1
                    x //= i
                factor.append((i, cnt))
        if x > 1:
            factor.append((x, 1))
        return factor

    factor = collections.defaultdict(int)
    for num in nums:
        for k, v in getFactor(num):
            factor[k] += v

    ans = 0
    for i in range(k, len(nums) + 1):
        temp = collections.defaultdict(int)
        flag = True
        for j in range(i - k, i):
            for k, v in getFactor(nums[j]):
                if k in temp and temp[k] != v:
                    flag = False
                    break
                else:
                    temp[k] = v
            if not flag:
                break
        if flag and temp in factor:
            ans += factor[temp]

    return ans

总结

通过哈希表优化,时间复杂度降为 $O(nk)$,但实际优化效果不是非常好,在特殊场景(如数组中元素过大)下还是会有性能瓶颈。因此,这种算法可以作为对暴力枚举的优化,对于较小规模的数据表现更加优秀。

同时,为了保证程序稳定性,可以针对输入进行一些必要的检查(如非负性、元素数量是否大于子数组长度等),以及对哈希表返回的结果进行类型判断、哈希表中的项进行筛选等操作。