Java 找到所有素数之和小于200万需要多少时间?

Java 找到所有素数之和小于200万需要多少时间?,java,algorithm,logic,primes,Java,Algorithm,Logic,Primes,我想解决这个问题。我在java中将euler的筛实现为一个助手类。对于较小的数字,它非常有效。但当我输入200万作为上限时,它不会返回答案。我使用netbeanside。有一次我等了好几个小时,但它还是没有打印出答案。当我停止运行代码时,它给出了以下结果 Java结果:2147483647 建造 成功(总时间:2097分钟) (43秒) 这个答案是不正确的。即使等了这么久,这也是不对的。而对于较小的限制,相同的代码返回正确的答案 欧拉筛有一个非常简单的算法 我的实施是: package supp

我想解决这个问题。我在java中将euler的筛实现为一个助手类。对于较小的数字,它非常有效。但当我输入200万作为上限时,它不会返回答案。我使用netbeanside。有一次我等了好几个小时,但它还是没有打印出答案。当我停止运行代码时,它给出了以下结果

Java结果:2147483647
建造 成功(总时间:2097分钟) (43秒)

这个答案是不正确的。即使等了这么久,这也是不对的。而对于较小的限制,相同的代码返回正确的答案

欧拉筛有一个非常简单的算法

我的实施是:

package support;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author admin
 */
public class SieveOfEuler {
    int upperLimit;
    List<Integer> primeNumbers;

    public SieveOfEuler(int upperLimit){
        this.upperLimit = upperLimit;
        primeNumbers = new ArrayList<Integer>();
        for(int i = 2 ; i <= upperLimit ; i++)
            primeNumbers.add(i);
        generatePrimes();
    }

    private void generatePrimes(){
        int currentPrimeIndex = 0;
        int currentPrime = 2;
        while(currentPrime <= Math.sqrt(upperLimit)){
            ArrayList<Integer> toBeRemoved = new ArrayList<Integer>();
            for(int i = currentPrimeIndex ; i < primeNumbers.size() ; i++){
                int multiplier = primeNumbers.get(i);
                toBeRemoved.add(currentPrime * multiplier);
            }

            for(Integer i : toBeRemoved){
                primeNumbers.remove(i);
            }

            currentPrimeIndex++;
            currentPrime = primeNumbers.get(currentPrimeIndex);
        }
    }

    public List getPrimes(){
        return primeNumbers;
    }

    public void displayPrimes(){
        for(double i : primeNumbers)
            System.out.println(i);
    }
}
包支持;
导入java.util.ArrayList;
导入java.util.List;
/**
*
*@author-admin
*/
公共级西弗勒{
整数上限;
列出素数;
公共Sieveofueler(整数上限){
这个。上限=上限;
素数=新的ArrayList();
对于(int i=2;i而(currentPrime一些明显的错误:

while(currentPrime <= Math.sqrt(upperLimit))
你至少应该进行明显的优化,只测试奇数。你已经知道偶数不是素数。这将把你的时间减少一半


此外,您正在使用蛮力方法来查找素数。对于较大的上限,这将非常缓慢。您应该使用更好的算法进行搜索-您将能够在web上找到更多信息,但我不知道这是否符合Euler项目的精神。

您的筛选速度如此缓慢的原因是您已经一个根本性的错误。
素数
应该是一个布尔数组,而不是一个
列表
。完成后,
primeNumbers[i]
的值对于素数为
true
,对于复合数为
false

这就是为什么它会有如此大的不同:

  • 在数组中设置或清除标志是
    O(1)
    ;即每次操作的一个小的恒定时间
  • ArrayList
    中删除元素是
    O(N)
    ,其中
    N
    是列表的大小…而且非常大
  • 每个
    ArrayList.remove(…)
    操作都必须搜索列表。如果该值不再存在(因为您已经删除了它),则remove操作每次调用时都必须查看列表中的每个剩余元素…最多200万个
  • ArrayList.remove(…)
    找到一个元素时,它会通过将元素索引后的所有剩余元素复制到备份数组的左侧来删除该元素。同样,每次删除一个元素时,最多会复制200万个条目
我希望实现良好的Erasothenes筛选能够在几秒钟内计算出所有少于200万的素数。

for(int I=currentPrimeIndex;Ifor(int i = currentPrimeIndex ; i < primeNumbers.size() ; i++){
    int multiplier = primeNumbers.get(i);
    toBeRemoved.add(currentPrime * multiplier);
}
整数乘数=素数。获取(i); toBeRemoved.add(currentPrime*乘数); }
在第一步中,这将生成一个2的200万倍的ArrayList(toBeRemoved)

然后它在toBeRemoved上迭代,为toBeRemoved中的每个条目扫描一次包含200万个候选素数的整个数组。toBeRemoved中的一半值不可能位于
素数中,因为它们太大。每次删除都会导致每个值的索引都大于删除的值,并向下移动一个位置

我认为这是效率低下的主要原因。实现Eratosthenes筛选的通常方法是创建一个包含200万个布尔值的数组,最初都是真的。当
I
被确定为非素数时,设置
可能为素数[I]
设置为false。若要查找下一个素数,请向前扫描以查找
true
值。若要在末尾获得所有素数的列表,请迭代数组,记录每个
true
值的索引。对于Euler的筛选,您应该执行大致相同的操作


您不需要对高达200万个素数进行优化。

要回答本主题标题中的问题:这是Euler项目网站所说的:

我已经写了我的程序,但需要几天才能找到答案吗? 绝对不是!每个问题都是根据的“一分钟规则”设计的,这意味着尽管设计一个具有更困难问题的成功算法可能需要几个小时,但高效的实现将允许在一台功率适中的计算机上在不到一分钟的时间内获得解决方案

;-)

  • 列表类型是否正确?在
    remove(obj)
    期间,集合的性能会更好。在您的情况下,请尝试
    BitSet

  • 您首先创建一个(长)要删除的元素列表,然后逐个删除它们。为什么不简单地删除它们呢

  • 结果不适用于
    int

  • import java.util.*;
    公共类素数和
    {
    公共静态int-isPrime(int-num)
    {
    整数和=0;
    整数因子=1;
    
    而(factor即使没有筛选,这个问题也可以在不到1秒的复杂度内解决。要检查一个数字是否为素数:


    对所有数字执行此操作并求和。

    这里有一个使用简单的埃拉斯托烯筛的解决方案:

    function sumPrimes(n)
        sum, sieve := 0, makeArray(2..n, True)
        for p from 2 to n
            if sieve[p]
                sum := sum + p
                for i from p*p to n step p
                    sieve[i] := False
        return sum
    

    我用Python编写了这个解决方案,需要1.25秒。如果你对素数编程感兴趣,我在我的博客上谦虚地推荐这个解决方案。

    当你筛选时得到的数字是什么?除了速度之外,检查前200万个素数的总和不适合
    int
    ,结果是什么显示值可疑地等于整数。如果使用袖珍计算器并手动计算,最大值可能需要更长的时间:)@robert我得到了正确的pr
    currentPrimeIndex++;
    
    for(int i = currentPrimeIndex ; i < primeNumbers.size() ; i++){
        int multiplier = primeNumbers.get(i);
        toBeRemoved.add(currentPrime * multiplier);
    }
    
    import java.util.*;
    
    public class PrimeSum
    {
        public static int isPrime(int num)
        {
            int sum = 0;
            int factor = 1;
            while(factor <= num)
            {
                if(num % factor != 0)
                {
                    sum += factor;
                    factor ++;
                }
                else
                {
                    factor ++;
                }
            }
            return sum;
        }
    
        public static void main(String[] args)
        {
            System.out.println("The program gets the sum of all prime numbers.");
    
            Scanner scan = new Scanner(System.in);
    
            System.out.print("Enter a number: ");
            int num = scan.nextInt();
    
            int sum = isPrime(num);
    
            System.out.println(sum);
        }
    }
    
    function sumPrimes(n)
        sum, sieve := 0, makeArray(2..n, True)
        for p from 2 to n
            if sieve[p]
                sum := sum + p
                for i from p*p to n step p
                    sieve[i] := False
        return sum