关于素数:代码不会停止运行,在 Java 中

the code doesn't stop running, in Java

我正在用 Java 解决项目 Euler 中的问题 10,即

"The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million."

我的代码是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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;
 }
}

但是代码没有给我任何结果,它没有停止运行。为什么?


通过一个小小的改变,你可以极大地提高性能:

变化:

1
for (int i = 2; i < n; i++) {

收件人:

1
2
int max = Math.sqrt(n);
for (int i = 2; i <= max; i++) {

你只需要检查到数字的平方根,因为在上升的过程中已经发现了更大的因素。

进行此更改会将您的算法从 O(n2) 更改为 O(n log(n))(我认为)。您的代码没有输出任何内容,因为运行时间太长 - 更改应该有望在合理的时间内为您提供答案。


您的代码运行时间是 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) 第二个和是谐波数,它的和在 O(logn) 中,所以这给了你 O(n-logn)=O(n) 运行时间。

由于这是针对每个数字完成的,因此总共会给出 O(n^2).

@Bohemian 更改为 int max = Math.sqrt(n); 的方法将产生 O(nsqrt(n)) 性能,如该线程中所述。

就时间复杂度而言,最好的方法是使用像 Sieve of Eratosthenes 之类的东西,它会产生 O(nlogn) 时间性能,这在渐近上优于您的算法和优化的算法,因此对于大型算法运行速度会明显更快数字。