[英]Need help calculating the amount of different prime factors of every number up to a given number
I want to calculate the amount of different prime factors of every integer up to n.我想计算每个 integer 最多 n 的不同质因数的数量。 For example, 12 = 2 * 2 * 3, so it has 2 different prime factors, 2 and 3. I want to store each of these values in an array result[], of size n+1, in which result[i] contains the number of different prime factors of the integer i.
例如,12 = 2 * 2 * 3,所以它有 2 个不同的质因数,2 和 3。我想将这些值中的每一个存储在一个数组 result[] 中,大小为 n+1,其中 result[i]包含 integer i 的不同质因数的数量。
I have to use the following external method in my solution:我必须在我的解决方案中使用以下外部方法:
List<Integer> getPrimes(int n) {
// create array to determine which numbers are prime
boolean isPrime[] = new boolean[n+1];
for(int i=2; i<=n; i++)
isPrime[i] = true; // assume all are prime, we'll filter below
for(int i=3; i*i<=n; i+=2) {
if (isPrime[i]) { // i is prime, so...
for(int j=i*i; j<=n; j+=i) // remove all its multiples
isPrime[j] = false; // by updating array
}
}
// create list with only the prime numbers
List<Integer> primes = new LinkedList<>();
primes.add(2);
for(int i=3; i<=n; i+=2)
if (isPrime[i])
primes.add(i);
return primes;
}
which uses the Sieve of Eratosthenes to return a List of all prime numbers up to n.它使用 Eratosthenes 的 Sieve 返回一个包含所有素数的列表,最多为 n。 This was my solution:
这是我的解决方案:
int[] getNumPrimeFactors(int n) {
int[] result = new int[n + 1];
int counter; // counts the number of different prime factors
boolean isPrime = true;
List<Integer> primeList = getPrimes(n);
for (int i = 2; i < result.length; i++) {
counter = 0;
// checks if i is prime
if (i % 2 == 0) {
isPrime = false;
} else {
for (int j = 3; j * j <= i; j += 2) {
if (i % j == 0)
isPrime = false;
}
}
// if i isnt prime, counts how many different prime factors it has
if (!isPrime) {
for (int prime : primeList) {
if (i % prime == 0)
counter++;
}
result[i] = counter;
} else {
result[i] = 1;
}
}
return result;
}
This algorithm produces the correct results, however, I want to be able to test for n <= 5_000_000, and it isn't efficient enough.该算法产生正确的结果,但是,我希望能够测试 n <= 5_000_000,但效率不够。 Is there any way I can improve the code for very large instances of n?
有什么办法可以改进非常大的 n 实例的代码吗? Here are some example test results:
以下是一些示例测试结果:
Thank you very much for your help:)非常感谢您的帮助:)
This is definitely not the most effective algorithm, but on my old computer (i5 3570K) it works up to 5_000_000 slightly more than 10 seconds.这绝对不是最有效的算法,但在我的旧电脑 (i5 3570K) 上,它可以运行 5_000_000 略多于 10 秒。 Sum of result array for 5_000_000 is 14838426.
5_000_000 的结果数组的总和为 14838426。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static List<Integer> primeFactors(int number) {
int n = number;
List<Integer> factors = new ArrayList<Integer>();
for (int i = 2; i <= n / i; i++) {
while (n % i == 0) {
factors.add(i);
n /= i;
}
}
if (n > 1) {
factors.add(n);
}
return factors;
}
public static void main(String[] args) {
int[] result = new int[5_000_001];
for (int i = 0; i < result.length; i++) {
result[i] = (int) primeFactors(i).stream().distinct().count();
}
System.out.println(Arrays.stream(result).sum());
}
}
One standard "improvement" I often find useful on sieving in this way is set up least prime factors for all the values (instead of just a "true/false" value).我经常发现以这种方式筛选有用的一个标准“改进”是为所有值设置最小主要因素(而不仅仅是“真/假”值)。 Then the "is it prime" decision is a check on whether the least prime factor
lpf
is less than the value.那么“它是素数”的决定是检查最小素数因子
lpf
是否小于该值。 This is basically nearly as quick as the prime sieve but then gives a more direct route to factorizing numbers in range.这基本上几乎与主筛一样快,但随后提供了一种更直接的方法来分解范围内的数字。
In Python:在 Python 中:
lim = 5000000+1
# precalc all least prime factors for composites in range
lpf = [i for i in range(lim)]
for m in range(4,lim,2):
lpf[m] = 2
k = 3
while k*k <= lim:
if lpf[k] == k:
for m in range(k*k, lim, 2*k):
if lpf[m] == m:
lpf[m] = k
k += 2
print('lpf done',lim) ############
# find number of distinct prime factors for each
result = [0]*lim
for a in range(2,lim):
pf = lpf[a]
fc = 1
res = a
while pf < res:
res //= pf
if pf != lpf[res]:
fc += 1
pf = lpf[res]
result[a] = fc
print(result[:11])
print(sum(result[:10+1]))
print(sum(result[:1234+1]))
print(sum(result[:1000000+1]))
The sieve here takes just over two seconds, which is about a quarter of the total time.这里的筛子只需要两秒钟多一点,大约是总时间的四分之一。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.