问题描述
小F正在研究一个数组,并想要计算出其中的连续子数组的某种特性。给定一个整数数组,你需要编写一个函数来返回乘积末尾零的数量大于等于 x 的连续子数组的数量。
由于答案可能非常大,你需要将结果对 10^9 + 7 取模后再返回。
问题理解
我们需要计算数组中连续子数组的数量,这些子数组的乘积末尾零的数量大于等于 x。末尾零的数量取决于乘积中因子 2 和 5 的数量,取两者的最小值。
解题思路
- 计算因子数量:首先,我们需要计算数组中每个元素的因子
2和5的数量。 - 前缀和:使用前缀和数组来记录从数组开头到当前位置的因子
2和5的累计数量。 - 子数组遍历:遍历所有可能的子数组,并利用前缀和数组计算每个子数组的因子
2和5的数量。 - 末尾零的计算:对于每个子数组,计算其末尾零的数量,并与
x进行比较。 - 结果统计:统计满足条件的子数组数量,并对结果取模
10^9 + 7。
具体步骤
-
计算每个数的因子数量:
- 编写一个函数
count_factors(num),用于计算一个数中因子2和5的数量。
- 编写一个函数
-
构建前缀和数组:
- 创建两个前缀和数组
prefix_count2和prefix_count5,分别记录从数组开头到当前位置的因子2和5的累计数量。
- 创建两个前缀和数组
-
遍历子数组:
- 使用双层循环遍历所有可能的子数组
[i, j]。 - 利用前缀和数组计算子数组
[i, j]的因子2和5的数量。
- 使用双层循环遍历所有可能的子数组
-
计算末尾零的数量:
- 对于每个子数组,计算其末尾零的数量
min(count2, count5)。 - 如果末尾零的数量大于等于
x,则结果加1。
- 对于每个子数组,计算其末尾零的数量
-
结果取模:
- 对结果取模
10^9 + 7,以防止溢出。
- 对结果取模
代码实现
def solution(a: list, x: int) -> int:
MOD = 10**9 + 7
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
prefix_count2 = [0] * (len(a) + 1)
prefix_count5 = [0] * (len(a) + 1)
for i in range(len(a)):
count2, count5 = count_factors(a[i])
prefix_count2[i + 1] = prefix_count2[i] + count2
prefix_count5[i + 1] = prefix_count5[i] + count5
result = 0
for i in range(len(a)):
for j in range(i, len(a)):
count2 = prefix_count2[j + 1] - prefix_count2[i]
count5 = prefix_count5[j + 1] - prefix_count5[i]
zeros = min(count2, count5)
if zeros >= x:
result = (result + 1) % MOD
return result
关键步骤解释
count_factors函数:用于计算一个数中因子2和5的数量。- 前缀和数组:
prefix_count2和prefix_count5分别记录从数组开头到当前位置的因子2和5的累计数量。 - 双层循环:遍历所有可能的子数组,并利用前缀和数组计算每个子数组的因子
2和5的数量。 - 末尾零的计算:通过
min(count2, count5)计算末尾零的数量,并与x进行比较。
时间复杂度
当前代码的主要时间复杂度来自于以下几个部分:
-
计算每个数的因子数量:
- 对于每个数,计算因子
2和5的数量。这个操作的时间复杂度是O(log n),其中n是数组中的最大值。 - 由于数组中有
n个数,因此这部分的总时间复杂度是O(n log n)。
- 对于每个数,计算因子
-
构建前缀和数组:
- 遍历数组并计算前缀和数组。这个操作的时间复杂度是
O(n)。
- 遍历数组并计算前缀和数组。这个操作的时间复杂度是
-
遍历所有可能的子数组:
- 使用双层循环遍历所有可能的子数组
[i, j]。这个操作的时间复杂度是O(n^2)。 - 对于每个子数组,计算因子
2和5的数量,这个操作的时间复杂度是O(1)。
- 使用双层循环遍历所有可能的子数组
综合以上部分,总的时间复杂度是 O(n log n) + O(n) + O(n^2)。由于 O(n^2) 是最高阶项,因此总的时间复杂度是 O(n^2)。
空间复杂度
当前代码的主要空间复杂度来自于以下几个部分:
-
前缀和数组:
prefix_count2和prefix_count5分别记录从数组开头到当前位置的因子2和5的累计数量。这两个数组的大小都是n + 1。- 因此,这部分的空间复杂度是
O(n)。
-
其他变量:
- 其他变量(如
count2、count5、zeros等)的空间复杂度是O(1)。
- 其他变量(如
综合以上部分,总的空间复杂度是 O(n)。
总结
- 时间复杂度:
O(n^2) - 空间复杂度:
O(n)