【问题标题】:Project Euler #10 Java solution not workingProject Euler #10 Java 解决方案不起作用
【发布时间】:2011-03-03 23:52:46
【问题描述】:

我试图找到

打印“sum”给出:1308111344,这是不正确的。

编辑: 感谢所有的帮助。将 int 更改为 long 并将

/*
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
*/
class Helper{
 public void run(){
  Integer sum = 0;
  for(int i = 2; i < 2000000; i++){
   if(isPrime(i))
    sum += i;   
  }
  System.out.println(sum);
 }

 private boolean isPrime(int nr){
  if(nr == 2)
   return true;
  else if(nr == 1)
   return false;
  if(nr % 2 == 0)
   return false;

  for(int i = 3; i < Math.sqrt(nr); i += 2){
   if(nr % i == 0)
    return false;
  }  
  return true;  
 }
}   
class Problem{
 public static void main(String[] args){
  Helper p = new Helper();
p.run();
}
}

【问题讨论】:

  • 作为提示,我会将 Math.sqrt(nr) 放在 for 条件之外,因此不会在每个循环中每次都对我进行评估,例如:stop = Math.sqrt(nr) (也可以使用 ceil,以避免浮点舍入错误) for(int i = 3; i

标签: java math primes


【解决方案1】:

结果将太大而无法放入整数,因此您将获得overflow。尝试改用BigIntegerlong。在这种情况下,一个 long 就足够了。

【讨论】:

  • 这不是问题,或者至少不是唯一的问题。
  • long 会比 BigInteger 更好[更快]。它显然足够大,因为 1 + 2 + 3 + ... + 2000000 = 2000001000000 小于 long 的最大值。
  • @Pointy:在两个错误中,这个是给出最大误差的一个。但是这两个错误都会导致答案错误。不幸的是,没有办法接受两个答案,所以如果你愿意,可以将我的答案复制到你的答案中并接受荣耀。 ;)
  • 是的,你是对的;我不确定它是否会挤进去,但又喝了 1/2 杯咖啡,然后我做了基本的数学运算。当我做那些 Project Euler 问题时,我使用了 Erlang,所以我不必担心整数大小(所有 Erlang 整数都像“BigInteger”):-)
【解决方案2】:

您将那些只能被平方根整除的数字(如 25)视为素数。而不是i &lt; Math.sqrt(nr) 尝试i &lt;= Math.sqrt(nr)

顺便说一句,这是一种非常低效的求素数的方法。

【讨论】:

  • 哇,为什么开车投反对票?该算法实际上是错误的,原因我在这里陈述。
  • 错了。他从 3 循环到数字的平方根。如果数字是,假设是 25——你不需要检查任何高于 5 的东西。如果有高于 5 的除数——那么另一个除数将低于 5,并且会在开始时被检查循环。
  • 没有循环到平方根!!他使用的比较是&lt; 而不是&lt;=
  • 啊,你是对的,我有点误解了你的反应。抱歉,我的投票倒置了:D
【解决方案3】:

您的 isPrime 不适用于正方形。 isPrime(9) 返回 true。

【讨论】:

    【解决方案4】:

    如前所述,错误有两个:

    • 您使用的int 不足以容纳该金额..您应该使用long
    • 您使用 &lt; 而不是 &lt;=,这是循环的错误保护

    除此之外,您所做的确实效率低下,无需深入了解此类算法(例如 Miller-Rabin 测试),我建议您查看Sieve of Eratosthenes .. 一种非常古老的方法,它教授如何以简单的方式处理复杂问题,以通过权衡内存来提高优雅和效率。

    它真的很聪明:它会跟踪每个素数的 boolean 值,直到 200 万个,断言该数字是否为素数。然后从第一个素数开始,它排除了通过将它正在分析的素数乘以另一个数字而获得的所有连续数字。当然,它需要检查的数量更多,需要检查的数字更少(因为它已经排除了它们)

    代码很简单(只是即时编写,没有检查):

        boolean[] numbers = new boolean[2000000];
        long sum = 0;
    
        for (int i = 0; i < numbers.length; ++i)
            numbers[i] = true;
    
        for (int i = 2; i < numbers.length; ++i)
            if (!numbers[i])
                continue;
            else {
                int j = i + i;
                while (j < 2000000) {                   
                    numbers[j] = false;
                    j += i;
                }           
            }
    
        for (int i = 2; i < 2000000; ++i)
            sum += numbers[i] ? i : 0;
    
        System.out.println(sum);
    

    当然,这种方法仍然不适合大数字(因为它必须找到所有先前的素数并且因为内存),但它是初学者思考问题的一个很好的例子..

    【讨论】:

    • 使用 bitset 是一个非常好的主意,我希望有好的旧 JIT java 编译器自己做这些优化:)
    • 另请注意,它从i * i 开始消除倍数,低于该倍数的所有倍数必须被一个较小的因子消除。这是一个很大的收获。
    【解决方案5】:

    这是我的解决方案

      public class ProjectEuler {
    
        public static boolean isPrime(int i) {
            if (i < 2) {
                return false;
            } else if (i % 2 == 0 && i != 2) {
                return false;
            } else {
                for (int j = 3; j <= Math.sqrt(i); j = j + 2) {
                    if (i % j == 0) {
                        return false;
                    }
                }
    
                return true;
            }
        }
    
    
        public static long sumOfAllPrime(int number){
            long sum = 2;
    
            for (int i = 3; i <= number; i += 2) {
                if (isPrime(i)) {
                    sum += i;
                }
            }
    
            return sum;
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            System.out.println(sumOfAllPrime(2000000));
        }
    }
    

    【讨论】:

      【解决方案6】:

      通过有效地使用Sieve of Eratosthenes,我解决了问题,这是我的代码

      public class SumOfPrime {
      
          static void findSum()
          {
              long i=3;
              long sum=0;
              int count=0;
              boolean[] array = new boolean[2000000];
              for(long j=0;j<array.length;j++)
              {
               if((j&1)==0)
                array[(int)j]=false;   
               else    
               array[(int)j]=true;
              }
              array[1]=false;
              array[2]=true;
              for(;i<2000000;i+=2)
              { 
                  if(array[(int)i] & isPrime(i))
                  {   
                      array[(int)i]=true;
                      //Sieve of Eratosthenes
                      for(long j=i+i;j<array.length;j+=i)
                          array[(int)j]=false;
                  }
              }
              for(int j=0;j<array.length;j++)
              {
                  if(array[j])
                  {   
                   //System.out.println(j);
                   count++;   
                   sum+=j;
                  }
              }   
              System.out.println("Sum="+sum +" Count="+count);
          }
          public static boolean isPrime(long num)
          {
              boolean flag=false;
              long i=3;
              long limit=(long)Math.sqrt(num);
              for(;i<limit && !(flag);i+=2)
              {
                  if(num%i==0)
                  {
                      flag=false;
                      break;
                  }   
              }
              if(i>=limit)
               flag=true;
              return flag;
          }
      
          public static void main(String args[])
          {
              long start=System.currentTimeMillis();
              findSum();
              long end=System.currentTimeMillis();
              System.out.println("Time for execution="+(end-start)+"ms");
          }
      
      }
      

      输出是

      Sum=142913828922 Count=148933
      Time for execution=2360ms
      

      如有疑问,请告知

      【讨论】:

      • 您可以通过忽略偶数在同一空间中存储两倍的布尔值。它只需要一些算术来解析正确的索引。此外,由于 boolean 使用整个字节进行存储,因此您浪费了大量空间。您可以更好地使用位数组:msdn.microsoft.com/en-us/library/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-29
      • 2016-04-30
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2013-07-30
      相关资源
      最近更新 更多