题目传送门
题意简述
小F正在研究一个整数数组,并希望计算出其中的连续子数组的某种特性。具体来说,给定一个整数数组,你需要编写一个函数来返回乘积末尾零的数量大于等于 x 的连续子数组的数量。由于答案可能非常大,结果需要对 10^9+7 取模后返回。
解题思路
-
末尾零的计算:
-
一个数的末尾零的数量由其因数中2和5的数量决定。具体来说,乘积的末尾零的数量等于其因数中2和5的最小数量。
-
因此,我们需要计算每个子数组中2和5的因数数量,并找出它们的最小值。
2. 前缀和数组:
-
为了快速计算任意子数组的2和5因数的数量,我们使用前缀和数组 count2 和 count5。
-
count2[i] 表示从数组开始到第 i-1 个元素中2的因数总数,count5[i] 类似。
-
通过前缀和数组,我们可以在常数时间内计算任意子数组的2和5因数的数量。
-
双重循环遍历子数组:
-
通过双重循环遍历所有可能的子数组,计算每个子数组的2和5因数的数量差值,进而计算出末尾零的数量。
-
对于每个子数组,计算 total2 = count2[end + 1] - count2[start] 和 total5 = count5[end + 1] - count5[start]。
-
末尾零的数量为 Math.min(total2, total5)。
-
结果计数:
-
如果某个子数组的末尾零数量大于等于 x,则计数加一。
-
由于结果可能非常大,计数时需要对 10^9+7 取模。
代码实现
public class Main {
private static final int MOD = 1000000007;
public static int solution(int[] a, int x) {
int n = a.length;
int[] count2 = new int[n + 1];
int[] count5 = new int[n + 1];
// 计算前缀和数组
for (int i = 0; i < n; i++) {
count2[i + 1] = count2[i] + countFactors(a[i], 2);
count5[i + 1] = count5[i] + countFactors(a[i], 5);
}
int result = 0;
// 遍历所有子数组
for (int start = 0; start < n; start++) {
for (int end = start; end < n; end++) {
int total2 = count2[end + 1] - count2[start];
int total5 = count5[end + 1] - count5[start];
int zeros = Math.min(total2, total5);
if (zeros >= x) {
result = (result + 1) % MOD;
}
}
}
return result;
}
// 计算一个数中某个因数的数量
private static int countFactors(int num, int factor) {
int count = 0;
while (num % factor == 0 && num > 0) {
count++;
num /= factor;
}
return count;
}
public static void main(String[] args) {
System.out.println(solution(new int[]{5, 2, 3, 50, 4}, 2) == 6);
System.out.println(solution(new int[]{10, 5, 2, 1}, 3) == 0);
System.out.println(solution(new int[]{25, 4, 8}, 1) == 2);
}
}
时间复杂度分析
该算法的时间复杂度为 𝑂(𝑛^2),其中 𝑛 是数组的长度。主要的时间消耗在于双重循环遍历所有可能的子数组。虽然时间复杂度较高,但对于较小的数组仍然是可行的。
用到的算法和数据结构
-
前缀和数组:用于快速计算任意子数组的2和5因数的数量。
-
双重循环:用于遍历所有可能的子数组。
详细分析
在实现过程中,我们首先通过 countFactors 函数计算每个元素中2和5的因数数量,并构建前缀和数组 count2 和 count5。接下来,通过双重循环遍历所有可能的子数组,计算每个子数组的2和5因数的数量差值,进而计算出末尾零的数量。最后,统计末尾零数量大于等于 x 的子数组数量,并对结果取模。这种方法通过前缀和数组的使用,能够在常数时间内计算任意子数组的2和5因数的数量,从而提高了效率。尽管双重循环的时间复杂度较高,但对于中小规模的数据集,该方法仍然是可行的。