📌  相关文章
📜  最小子数组,除以数组大小,其乘积剩下余数K(1)

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

最小子数组乘积余数问题

问题描述

给定一个整数数组 nums 和一个正整数 k,求最小的子数组的乘积除以数组大小的余数为 k。

示例
  • 输入: nums = [1,2,3,4], k = 4 输出: 0 解释: 最小的子数组为 [4],其乘积为 4,除以数组大小得 1,余数为 0,与 k 不符。

  • 输入: nums = [1,2,3,4], k = 10 输出: 2 解释: 最小的子数组为 [2,3],其乘积为 6,除以数组大小得 1,余数为 2,符合要求。

解题思路
  • 首先考虑暴力枚举:枚举所有子数组,计算它们乘积以及数组大小并判断是否符合要求。时间复杂度为 $O(n^3)$,无法通过本题。

  • 从题目中可以得到一个简单的结论:如果最小子数组的乘积为 k,那么直接返回 0 即可。

  • 不妨设当前考虑到的子数组为 $[l, r]$,它的乘积为 $p$,数组大小为 $s$。令 $x = p/s \pmod k$,则我们要求的就是 $x$。

  • 为了方便处理,我们可以将这个问题转化为:在模 $k$ 意义下,寻找最小的 $s$,使得 $p \equiv xs \pmod k$。这是一个常见的问题,可以使用哈希表来解决。具体而言,我们从左到右枚举子数组的右端点 $r$,用一个哈希表维护所有 $[l,r]$ 的乘积模 $k$ 的值以及最小的数组大小。当 $p \equiv xs \pmod k$ 时,说明我们找到了一个合法的子数组,更新答案。时间复杂度为 $O(n \log n)$。

  • 哈希表中的 key 应该存储 $p \bmod k$ 的值,而不是 $p$ 的值,防止在计算过程中超出整型范围。同时,每次更新答案之后都要将当前的乘积除以当前的数组大小,以便与后面的数组合并时方便计算。

参考代码
def find_min_subarray(nums: List[int], k: int) -> int:
    n = len(nums)
    h = {0: -1}  # 初始哈希表,表示前 0 个数的积是 1,模 k 的值是 0
    p, s, ans = 1, 0, n + 1  # p 表示 nums[l:r+1] 的积,s 表示 nums[l:r+1] 的长度,ans 表示最终答案
    for r in range(n):
        if nums[r] % k == 0:
            p, s = 1, 0  # 如果当前数是 k 的倍数,就直接把 p 和 s 设为 1 和 0
        else:
            p *= nums[r]
            s += 1
        x = p % k
        if x in h:
            ans = min(ans, (s - h[x]))
        h.setdefault(x, s)  # 如果 x 不在哈希表中,就把它加进去
        p /= nums[r - s]  # 窗口向右移动,需要把左端点对应的数从积中去掉
    return ans if ans <= n else -1

以上是 python 版本的代码。这个问题也可以使用哈希表实现,不过 C++ 版本的代码可能会更长一点,因为需要手动把整数转化为字符串再放进哈希表中。