动态规划和前缀和问题|豆包MarsCode AI刷题

101 阅读3分钟

在豆包MarsCode刷题过程中遇到这样一道题

问题描述

小F正在研究一个数组,并想要计算出其中的连续子数组的某种特性。给定一个整数数组,你需要编写一个函数来返回乘积末尾零的数量大于等于 x 的连续子数组的数量。

由于答案可能非常大,你需要将结果对 10^9 + 7 取模后再返回。

这道题属于动态规划前缀和的题型。我们需要计算数组中连续子数组的乘积末尾零的数量,并统计符合条件的子数组数量。

解题思路

  1. 理解问题

    • 末尾零的数量取决于乘积中因子2和因子5的数量,因为每个末尾零对应一个因子2和一个因子5的组合。
    • 我们需要找到所有连续子数组,使得其乘积末尾零的数量大于等于 x
  2. 数据结构的选择

    • 使用前缀和数组来记录从数组开头到当前位置的因子2和因子5的数量。
  3. 算法步骤

    • 计算每个数的因子2和因子5的数量:对于每个数,计算它包含的因子2和因子5的数量。
    • 构建前缀和数组:使用前缀和数组来记录从数组开头到当前位置的因子2和因子5的数量。
    • 计算子数组的末尾零数量:对于每个可能的子数组,通过前缀和数组计算因子2和因子5的数量,并判断其末尾零的数量是否大于等于 x
    • 统计符合条件的子数组数量:遍历所有可能的子数组,统计符合条件的子数组数量,并对结果取模 10^9 + 7

具体代码实现

def solution(a: list, x: int) -> int:
    MOD = 10**9 + 7
    
    # 计算每个数的因子2和因子5的数量
    def count_factors(num):
        count2, count5 = 0, 0
        while num % 2 == 0:
            num //= 2
            count2 += 1
        while num % 5 == 0:
            num //= 5
            count5 += 1
        return count2, count5
    
    # 计算前缀和数组
    prefix2 = [0] * (len(a) + 1)
    prefix5 = [0] * (len(a) + 1)
    for i in range(len(a)):
        count2, count5 = count_factors(a[i])
        prefix2[i + 1] = prefix2[i] + count2
        prefix5[i + 1] = prefix5[i] + count5
    
    # 统计符合条件的子数组数量
    result = 0
    for i in range(len(a)):
        for j in range(i, len(a)):
            # 计算子数组 [i, j] 的因子2和因子5的数量
            count2 = prefix2[j + 1] - prefix2[i]
            count5 = prefix5[j + 1] - prefix5[i]
            # 计算末尾零的数量
            zeros = min(count2, count5)
            # 判断是否符合条件
            if zeros >= x:
                result = (result + 1) % MOD
    
    return result

if __name__ == '__main__':
    print(solution(a = [5, 2, 3, 50, 4], x = 2) == 6)
    print(solution(a = [10, 5, 2, 1], x = 3) == 0)
    print(solution(a = [25, 4, 8], x = 1) == 2)

关键步骤解释

  1. count_factors 函数:用于计算一个数中因子2和因子5的数量。
  2. 前缀和数组prefix2 和 prefix5 分别记录从数组开头到当前位置的因子2和因子5的数量。
  3. 双层循环:遍历所有可能的子数组,计算每个子数组的末尾零的数量,并统计符合条件的子数组数量。

总结

  • 动态规划:通过前缀和数组记录因子2和因子5的数量。
  • 前缀和:利用前缀和数组快速计算子数组的因子2和因子5的数量。
  • 双层循环:遍历所有可能的子数组,计算每个子数组的末尾零的数量,并统计符合条件的子数组数量。