这是我找到素数总和的代码。它适用于一些较低的数字,但如果它2000000
(200万)它永远不会结束。任何人都可以帮助我吗?
import java.math.BigInteger;
public class Problem010{
public static void main(String[] args) {
BigInteger sum = new BigInteger("2");
//for (int i=3; i<2000000; i++) {
for(int i=3; i<10; i++){
for (int j=2; j<i; j++){
if (i % j == 0)
break;
else if (i == j+1){
sum = sum.add(BigInteger.valueOf(i));
}
}
}
System.out.println("Sum = "+sum);
}
}
答案 0 :(得分:9)
你的答案是142913828922
但是怎么样?
我刚刚改变了你的算法:
public static void main(String[] args) {
BigInteger sum = new BigInteger("2");
boolean isPrime = true;
for (int i=3; i<2000000; i++) {
double aa = Math.sqrt((double)i);
for (int j=2; j<=aa; j++){
if (i % j == 0){
isPrime = false;
break;
}
}
if(isPrime){
sum = sum.add(BigInteger.valueOf(i));
}
isPrime = true;
}
System.out.println("Sum = "+sum);
}
而不是遍历从2到i的所有数字,我只是从2到sqrt(i),这会大大改善你的代码运行时间:)
答案 1 :(得分:3)
@Lrrr,答案是对的。但算法可以进一步优化。看看我的isPrime
算法。对于200万,你不需要BigInteger
。
long sum = 2;// new BigInteger("2");
for (int i=3; i<2000000; i++) {
if(isPrime(i)) {
sum = sum + i;//.add(BigInteger.valueOf(i));
}
}
System.out.println("Sum = "+sum);
这是isPrime方法。
static boolean isPrime(int n) {
if (n < 2) {
return false;
}
if (n == 2 || n == 3) {
return true;
}
if ((n & 1) == 0 || n % 3 == 0) {
return false;
}
int sqrtN = (int) Math.sqrt(n) + 1;
for (int i = 6; i <= sqrtN; i += 6) {// loop 6 step
if (n % (i - 1) == 0 || n % (i + 1) == 0) {
return false;
}
}
return true;
}
答案 2 :(得分:2)
你可以使用Sieve of Eratosthenes算法,它比你的效率更高。
1)将所有数字存储在数组中的2和N之间,并将它们全部标记为素数。
2)从X = 2开始,并标记其所有i * X(2X,3X ..),其中i是自然数小于或等于N,乘数不是素数。不要标记X.
3)找到比未标记的X更大的下一个数字并重复该过程。如果没有这样的号码,请停止。
4)数组中的剩余数字是素数
这样的事情:
public static boolean [] findPrimes(int N){
boolean[] primes = new boolean[N + 1];
// assume that all numbers are prime within given range
for (int i = 2; i <= N; i++) {
primes[i] = true;
}
// for all numbers in range, starting from 2
for (int i = 2; i*i <= N; i++) {
// mark natural multiples of i as nonprime
if (primes[i]) {
for (int j = i; i*j <= N; j++) {
primes[i*j] = false;
}
}
return primes;
}
5)迭代返回的素数和TRUE值的和索引
答案 3 :(得分:2)
一个有效的解决方案可能是使用Sieve of Eratosthenes来找出低于2,000,000(或任何其他数字)的数字,而不是后处理并将它们全部加起来:
int n = 2000000;
boolean[] isPrime = new boolean[n];
//preprocess - set up the array
for (int i = 2; i<n;i++) isPrime[i] = true;
//run sieve:
for (int i = 2; i < (int) Math.sqrt(n) + 1; i++) {
if (isPrime[i]) {
for (int j = 2; j*i < n; j++) isPrime[i*j] = false;
}
}
//sum primes:
long sum = 0;
for (int i = 2; i < n; i++) {
if (isPrime[i]) sum+=i;
}
System.out.println(sum);
与每次检查每个号码相比,如果它是否为素数(需要O(sqrt(n))
- 并且通过对所有数字执行O(nsqrt(n))
,则在此处汇总以前的知识迭代,有效地将复杂性降低到O(nloglog(n))
,这对于足够大的n
值来说要快得多。
这需要O(n)
额外空间。
答案 4 :(得分:0)
我开发了自己的解决方案,它能在700毫秒内完成查找200万以下的所有内容。
我使用迭代方法,但我只是停止寻找大于(n / i)+1 的数字,其中 n 是要检查的数字是否为质数和 i 是迭代循环中的数字,以查看其是否为除数。
public void run () {
long sumOfPrimes = 2;
int maxNumber = 2000000;
int counter = 0;
for (int i = 3; i <= maxNumber; i = i+2) {
if(isPrimeOptimized(i)){
sumOfPrimes = sumOfPrimes + i;
counter ++;
}
}
System.out.println("num of primes is " + counter);
System.out.println("sum of primes is " + sumOfPrimes);
}
private boolean isPrimeOptimized(int n){
int limitToDivide = n;
for(int i=2;i<=limitToDivide && i<n;i++){
if(n%i == 0)
return false;
else
limitToDivide = (n/i) + 1;
}
return true;
}
答案 5 :(得分:-1)
到目前为止,还没有人真正正确地实施过Sieve。仔细检查维基百科页面,并注意如何循环数字。如果没有使用int(或布尔值)数组进行任何优化,那么在Java中只需要几秒钟。