在豆包MarsCode刷题过程中遇到这样一道题
问题描述
小F正在研究一个数组,并想要计算出其中的连续子数组的某种特性。给定一个整数数组,你需要编写一个函数来返回乘积末尾零的数量大于等于 x 的连续子数组的数量。
由于答案可能非常大,你需要将结果对 10^9 + 7 取模后再返回。
这道题属于动态规划和前缀和的题型。我们需要计算数组中连续子数组的乘积末尾零的数量,并统计符合条件的子数组数量。
解题思路
-
理解问题:
- 末尾零的数量取决于乘积中因子2和因子5的数量,因为每个末尾零对应一个因子2和一个因子5的组合。
- 我们需要找到所有连续子数组,使得其乘积末尾零的数量大于等于
x。
-
数据结构的选择:
- 使用前缀和数组来记录从数组开头到当前位置的因子2和因子5的数量。
-
算法步骤:
- 计算每个数的因子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)
关键步骤解释
count_factors函数:用于计算一个数中因子2和因子5的数量。- 前缀和数组:
prefix2和prefix5分别记录从数组开头到当前位置的因子2和因子5的数量。 - 双层循环:遍历所有可能的子数组,计算每个子数组的末尾零的数量,并统计符合条件的子数组数量。
总结
- 动态规划:通过前缀和数组记录因子2和因子5的数量。
- 前缀和:利用前缀和数组快速计算子数组的因子2和因子5的数量。
- 双层循环:遍历所有可能的子数组,计算每个子数组的末尾零的数量,并统计符合条件的子数组数量。