问题描述
小F正在研究一个数组,并想要计算出其中的连续子数组的某种特性。给定一个整数数组,你需要编写一个函数来返回乘积末尾零的数量大于等于 x 的连续子数组的数量。
由于答案可能非常大,你需要将结果对 10^9 + 7 取模后再返回。
测试样例
样例1:
输入:
a = [5, 2, 3, 50, 4] ,x = 2
输出:6
思路
-
计数因子:
对于每个数字,计算其包含的因子 2 和因子 5 的数量。
-
滑动窗口:
- 使用双重循环遍历所有可能的子数组。
- 外层循环确定子数组的起始位置
start。 - 内层循环从
start开始遍历到数组的末尾,计算当前子数组中因子 2 和因子 5 的数量。
-
检查条件:
如果当前子数组中因子 2 和因子 5 的最小值大于等于
x,则该子数组满足条件。 -
计数结果:
统计所有满足条件的子数组的数量,并对结果取模 10^9+7。
代码详解
假设输入数组 a = [5, 2, 3, 50, 4],x = 2。
第一次外层循环 (start = 0)
-
初始状态:
count2 = 0count5 = 0
-
第一次内层循环 (
end = 0) :num = 5count2 += countFactors(5, 2) = 0→count2 = 0count5 += countFactors(5, 5) = 1→count5 = 1Math.min(0, 1) < 2,不满足条件。
-
第二次内层循环 (
end = 1) :num = 2count2 += countFactors(2, 2) = 1→count2 = 1count5 += countFactors(2, 5) = 0→count5 = 1Math.min(1, 1) < 2,不满足条件。
-
第三次内层循环 (
end = 2) :num = 3count2 += countFactors(3, 2) = 0→count2 = 1count5 += countFactors(3, 5) = 0→count5 = 1Math.min(1, 1) < 2,不满足条件。
-
第四次内层循环 (
end = 3) :num = 50count2 += countFactors(50, 2) = 1→count2 = 2count5 += countFactors(50, 5) = 2→count5 = 3Math.min(2, 3) >= 2,满足条件。count++→count = 1
-
第五次内层循环 (
end = 4) :num = 4count2 += countFactors(4, 2) = 2→count2 = 4count5 += countFactors(4, 5) = 0→count5 = 3Math.min(4, 3) >= 2,满足条件。count++→count = 2
第二次外层循环 (start = 1)
-
初始状态:
count2 = 0count5 = 0
-
第一次内层循环 (
end = 1) :num = 2count2 += countFactors(2, 2) = 1→count2 = 1count5 += countFactors(2, 5) = 0→count5 = 0Math.min(1, 0) < 2,不满足条件。
-
第二次内层循环 (
end = 2) :num = 3count2 += countFactors(3, 2) = 0→count2 = 1count5 += countFactors(3, 5) = 0→count5 = 0Math.min(1, 0) < 2,不满足条件。
-
第三次内层循环 (
end = 3) :num = 50count2 += countFactors(50, 2) = 1→count2 = 2count5 += countFactors(50, 5) = 2→count5 = 2Math.min(2, 2) >= 2,满足条件。count++→count = 3
-
第四次内层循环 (
end = 4) :num = 4count2 += countFactors(4, 2) = 2→count2 = 4count5 += countFactors(4, 5) = 0→count5 = 2Math.min(4, 2) >= 2,满足条件。count++→count = 4
第三次外层循环 (start = 2)
-
初始状态:
count2 = 0count5 = 0
-
第一次内层循环 (
end = 2) :num = 3count2 += countFactors(3, 2) = 0→count2 = 0count5 += countFactors(3, 5) = 0→count5 = 0Math.min(0, 0) < 2,不满足条件。
-
第二次内层循环 (
end = 3) :num = 50count2 += countFactors(50, 2) = 1→count2 = 1count5 += countFactors(50, 5) = 2→count5 = 2Math.min(1, 2) < 2,不满足条件。
-
第三次内层循环 (
end = 4) :num = 4count2 += countFactors(4, 2) = 2→count2 = 3count5 += countFactors(4, 5) = 0→count5 = 2Math.min(3, 2) >= 2,满足条件。count++→count = 5
第四次外层循环 (start = 3)
-
初始状态:
count2 = 0count5 = 0
-
第一次内层循环 (
end = 3) :num = 50count2 += countFactors(50, 2) = 1→count2 = 1count5 += countFactors(50, 5) = 2→count5 = 2Math.min(1, 2) < 2,不满足条件。
-
第二次内层循环 (
end = 4) :num = 4count2 += countFactors(4, 2) = 2→count2 = 3count5 += countFactors(4, 5) = 0→count5 = 2Math.min(3, 2) >= 2,满足条件。count++→count = 6
第五次外层循环 (start = 4)
-
初始状态:
count2 = 0count5 = 0
-
第一次内层循环 (
end = 4) :num = 4count2 += countFactors(4, 2) = 2→count2 = 2count5 += countFactors(4, 5) = 0→count5 = 0Math.min(2, 0) < 2,不满足条件。
完整代码
public class Main {
public static int solution(int[] a, int x) {
final int MOD = 1_000_000_007;
int count = 0;
int n = a.length;
for (int start = 0; start < n; start++) {
int count2 = 0;
int count5 = 0;
for (int end = start; end < n; end++) {
int num = a[end];
count2 += countFactors(num, 2);
count5 += countFactors(num, 5);
if (Math.min(count2, count5) >= x) {
count++;
count %= MOD;
}
}
}
return count;
}
private static int countFactors(int num, int factor) {
int count = 0;
while (num % factor == 0) {
num /= factor;
count++;
}
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 和因子 5 中的较小值决定。