连续子数数组零尾数问题 | 豆包MarsCode AI刷题

67 阅读2分钟

题目理解

我们需要计算数组中连续子数组的数量,这些子数组的乘积末尾零的数量大于等于 x。末尾零的数量取决于乘积中因子 2 和 5 的数量,因为每个 10 都是由一个 2 和一个 5 相乘得到的。

数据结构的选择

我们可以使用两个变量来分别记录当前子数组中因子 2 和 5 的数量。

算法步骤

  1. 计算因子数量:对于数组中的每个元素,计算其包含的因子 2 和 5 的数量。
  2. 滑动窗口:使用滑动窗口技术来维护当前子数组中因子 2 和 5 的数量。
  3. 判断条件:在滑动窗口的过程中,判断当前子数组中因子 2 和 5 的最小数量是否大于等于 x
  4. 更新结果:如果满足条件,则更新结果,并移动窗口的左边界,直到条件不再满足。

关键点

  • 使用滑动窗口技术来动态维护当前子数组的因子数量。
  • 在每次移动右边界时,更新因子数量,并判断是否满足条件。
  • 如果满足条件,则计算当前右边界到数组末尾的所有可能子数组数量,并更新结果。

代码构思

  1. count_trailing_zeros 函数

    • 该函数用于计算一个数中因子 2 和 5 的数量。
    • 逻辑正确,没有问题。
  2. solution 函数

    • 变量初始化count_2 和 count_5 初始化为 0result 初始化为 0left 初始化为 0
    • 滑动窗口:使用 right 遍历数组,计算每个元素的因子 2 和 5 的数量,并更新 count_2 和 count_5
    • 条件判断:在 while 循环中,判断当前子数组中因子 2 和 5 的最小数量是否大于等于 x
    • 结果更新:如果满足条件,则更新 result,并移动 left 指针,减少因子数量。

代码展示

def count_trailing_zeros(n):
    count_2, count_5 = 0, 0
    while n % 2 == 0 and n > 0:
        count_2 += 1
        n //= 2
    while n % 5 == 0 and n > 0:
        count_5 += 1
        n //= 5
    return count_2, count_5

def solution(a: list, x: int) -> int:
    MOD = 10**9 + 7
    n = len(a)
    count_2, count_5 = 0, 0
    result = 0
    left = 0

    for right in range(n):
        c2, c5 = count_trailing_zeros(a[right])
        count_2 += c2
        count_5 += c5
        
        while left <= right and min(count_2, count_5) >= x:
            result = (result + (n - right)) % MOD
            c2_left, c5_left = count_trailing_zeros(a[left])
            count_2 -= c2_left
            count_5 -= c5_left
            left += 1

    return result
  • 时间复杂度*:

    • 当前实现:O(n^2)
    • 优化后实现:O(n)

总结

使用滑动窗口技术来动态维护当前子数组的因子数量,确保在 O(n) 时间内完成计算。