小C的连续自然数乘积问题 | 豆包MarsCode AI 刷题
在数学中,素数因子的分解是一个重要的概念。小S希望在 ([1, n]) 的范围内找到一些连续的自然数,这些数的乘积最多包含 ( k ) 个不同的素因子。你的任务是帮助小S找到可以取的连续自然数的最大长度。本文将探讨如何实现这一目标,并提供详细的代码实现。
问题描述
给定一个整数 ( n ) 和一个整数 ( k ),在 ([1, n]) 的范围内找到一些连续的自然数,这些数的乘积最多包含 ( k ) 个不同的素因子。目标是帮助小S找到可以取的连续自然数的最大长度。
解决方案
为了帮助小S找到可以取的连续自然数的最大长度,我们可以分以下几个步骤来实现:
- 素数筛选:
- 使用埃拉托斯特尼筛法(Sieve of Eratosthenes)生成 ([1, n]) 范围内的所有素数。
- 素因子分解:
- 对于每个数,记录其所有素因子。
- 滑动窗口:
- 使用滑动窗口技术,维护一个窗口内的不同素因子数量。
- 当窗口内的不同素因子数量超过 ( k ) 时,移动窗口的左边界,直到窗口内的不同素因子数量不超过 ( k )。
- 记录窗口的最大长度。
代码实现
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static int solution(int n, int k) {
boolean[] sieve = new boolean[n + 1];
for (int i = 0; i < sieve.length; i++) {
sieve[i] = true;
}
sieve[0] = false;
sieve[1] = false;
// 素数筛选
for (int i = 2; i <= Math.sqrt(n); i++) {
if (sieve[i]) {
for (int j = i * i; j <= n; j += i) {
sieve[j] = false;
}
}
}
ArrayList<Integer> primes = new ArrayList<>();
for (int i = 0; i < sieve.length; i++) {
if (sieve[i]) {
primes.add(i);
}
}
ArrayList<Integer>[] factors = new ArrayList[n + 1];
for (int i = 0; i < factors.length; i++) {
factors[i] = new ArrayList<>();
}
// 素因子分解
for (int prime : primes) {
for (int multiple = prime; multiple <= n; multiple += prime) {
factors[multiple].add(prime);
}
}
int left = 1;
int maxLength = 0;
Map<Integer, Integer> primeCounts = new HashMap<>();
int distinctPrimes = 0;
// 滑动窗口
for (int right = 1; right <= n; right++) {
for (int p : factors[right]) {
primeCounts.put(p, primeCounts.getOrDefault(p, 0) + 1);
if (primeCounts.get(p) == 1) {
distinctPrimes++;
}
}
while (distinctPrimes > k && left <= right) {
for (int p : factors[left]) {
int count = primeCounts.get(p);
if (count == 1) {
primeCounts.remove(p);
distinctPrimes--;
} else {
primeCounts.put(p, count - 1);
}
}
left++;
}
int currentLength = right - left + 1;
if (currentLength > maxLength) {
maxLength = currentLength;
}
}
return maxLength;
}
public static void main(String[] args) {
// 测试样例
System.out.println(solution(10, 3) == 6); // 输出:true
System.out.println(solution(20, 5) == 12); // 输出:true
System.out.println(solution(100, 4) == 10); // 输出:true
}
}
代码解释
- 素数筛选:
- 使用埃拉托斯特尼筛法生成 ([1, n]) 范围内的所有素数。
- 初始化一个布尔数组
sieve,默认所有数为素数。 - 从2开始,标记所有素数的倍数为非素数。
- 素因子分解:
- 对于每个数,记录其所有素因子。
- 使用一个二维数组
factors,其中factors[i]存储i的所有素因子。
- 滑动窗口:
- 使用滑动窗口技术,维护一个窗口内的不同素因子数量。
- 使用一个哈希表
primeCounts记录窗口内每个素因子的出现次数。 - 当窗口内的不同素因子数量超过 ( k ) 时,移动窗口的左边界,直到窗口内的不同素因子数量不超过 ( k )。
- 记录窗口的最大长度。
测试样例
- 样例1:
n = 10, k = 3,输出:6- 解释:在 ([1, 10]) 范围内,最长的连续自然数乘积最多包含3个不同素因子的子数组是 ([5, 6, 7, 8, 9, 10])。
- 样例2:
n = 20, k = 5,输出:12- 解释:在 ([1, 20]) 范围内,最长的连续自然数乘积最多包含5个不同素因子的子数组是 ([9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])。
- 样例3:
n = 100, k = 4,输出:10- 解释:在 ([1, 100]) 范围内,最长的连续自然数乘积最多包含4个不同素因子的子数组是 ([7, 8, 9, 10, 11, 12, 13, 14, 15, 16])。 通过上述方法,我们可以有效地帮助小S找到可以取的连续自然数的最大长度,确保在 ([1, n]) 范围内,连续自然数的乘积最多包含 ( k ) 个不同的素因子。