问题描述
小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)