我在Java中的项目Euler中解决问题10,这是
“10以下的素数之和为2 + 3 + 5 + 7 = 17 找出200万以下所有素数的总和。“
我的代码是
package projecteuler_1;
import java.math.BigInteger;
import java.util.Scanner;
public class ProjectEuler_1 {
public static void main(String[] args) {
int sum = 0, i = 2;
while (i <= 2000000) {
if (isPrime(i)) {
sum += i;
}
i++;
}
System.out.println(sum);
}
public static boolean isPrime(int n) {
int i, res;
boolean flag = true;
for (i = 2; i <= n / 2; i++) {
res = n % i;
if (res == 0) {
flag = false;
break;
}
}
return flag;
}
}
但代码没有给我任何结果,它不会停止运行。为什么呢?
答案 0 :(得分:2)
通过稍作改动,您可以极大地提高性能:
变化:
for (int i = 2; i < n; i++) {
要:
int max = Math.sqrt(n);
for (int i = 2; i <= max; i++) {
您只需要检查数字的平方根,因为在上升过程中已经找到了更大的因子。
进行此更改会将您的算法从O(n 2 )更改为O(n log(n))(我认为)。您的代码不会输出任何内容,因为它需要花费太长时间才能运行 - 更改应该可以在合理的时间内为您提供答案。
答案 1 :(得分:0)
您的代码运行时间为O(n^2)
。每次对isPrime()
的调用平均为O(n)
。
<强>解释强>
1/2
的数字可以除以2,1/3
可以除以3,... 1/n
可以被n
除。此方法的预期运行次数将为(1-1/2) + (1-1/3) +...+(1-1/n) = (1+1+..+1)-(1/2+1/3+..+1/n) = n - (1/2+1/3+...+1/n)
第二个和为harmonic number,其总和为O(logn)
,因此这将为您提供O(n-logn)=O(n)
运行时间。
由于这是按照每个号码完成的,因此它总计O(n^2)
。
@Bohemian更改为int max = Math.sqrt(n);
的方法将产生O(nsqrt(n))
效果,如in this thread所述。
时间复杂度方面的最佳方法是使用类似 Sieve of Eratosthenes 的内容,这会产生O(nlogn)
时间性能,这比您的算法渐近地好,并且优化的一个,因此对于大数字来说会更快地运行。