项目Euler#23 in Java

时间:2014-01-26 02:50:36

标签: java

我在Project Euler上花了很长时间研究问题#23。

以下程序给出的答案是 4190428 ,我无法弄清楚原因。

我认为某处可能存在一两个字符错误。

public long problem23() {

    ArrayList<Integer> abundantNumbers = new ArrayList<Integer>();
    int limit = 28123;
    for(int i = 2; i < limit; i++) {
        if(isAbundantNum(i)) {
            abundantNumbers.add(i);
        }
    }

    boolean [] abundantSum = new boolean [limit+1];
    for(int a = 0; a < abundantNumbers.size(); a++) {
        for(int b = 1; b < abundantNumbers.size(); b++) {
            int temp = abundantNumbers.get(a) + abundantNumbers.get(b); 
            if(temp <= limit) {
                abundantSum[temp] = true;
            } else {
                break;
            }
        }
    }
    long sum = 0;
    for(int i = 1; i <= limit; i++) {
        if(!abundantSum[i]) {
            sum += i;
        }
    }
    return sum;
}

public boolean isAbundantNum(int n) {
    int factorSum = 1;
    for(int i = 2; i < Math.sqrt(n); i++) {
        if(n%i == 0) {
            factorSum += i; factorSum += n/i; 
        }
    }
    if(factorSum > n) {
        System.out.println(n);
        return true;
    }
    return false;
}

修改:添加了isAbundantNum(int n)方法。

2 个答案:

答案 0 :(得分:2)

你有2个错误......

for(int b = 1; b < abundantNumbers.size(); b++) {

'b'应该从零开始而不是1

for(int i = 2; i < Math.sqrt(n); i++) {
    if(n%i == 0) {
        factorSum += i; factorSum += n/i; 
    }
}

这样的保理会给你重复(比如2 * 2 = 4,你得到两个)。

尝试类似:

    for(int i = 2; i < n; i++) {
        if(n%i == 0) {
            factorSum += i;
        }
    }

答案 1 :(得分:2)

这是另一个实现:

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

public class P23 {

    final static int MIN = 12;
    final static int MAX = 28123;
    static boolean numbers[] = new boolean[MAX+1];
    static List<Integer> abundantNumbers = new ArrayList();

    public static void main(String args[]) {
        generateAbundants(MIN, MAX);
        int size = abundantNumbers.size();
        for (int i = 0; i < size; i++) {
            for (int j = i; j < size; j++) {
                int current = abundantNumbers.get(i) + abundantNumbers.get(j);
                if (current <= MAX) {
                    numbers[current] = true;
                } else {
                    break;
                }
            }
        }
        long sum = 0;
        for (int i = 1 ; i <= MAX ; i++ ) {
            if ( numbers[i] == false ) {
                sum += i;
            }
        }
        System.out.println(sum);
    }

    private static int sumOfProperDivisors(int x) {
        int sum = 1;
        int squareRoot = (int) Math.sqrt(x);
        for (int i = 2; i <= squareRoot; i++) {
            if (x % i == 0) {
                sum += i;
                sum += x / i;
            }
        }
        // if x is a perfect square, it's square root was added twice
        if (squareRoot * squareRoot == x) {
            sum -= squareRoot;
        }
        return sum;
    }

    private static boolean isAbundant(int x) {
        if (x < sumOfProperDivisors(x)) {
            return true;
        }
        return false;
    }

    private static void generateAbundants(int min, int max) {
        for (int i = min; i < max; i++) {
            if (isAbundant(i)) {
                abundantNumbers.add(i);
            }
        }
    }

}

时间:455毫秒

<强>解释

  • j的默认值为i。您可以j = 0(正如Ted Bigham所说 - 在这种情况下为b),因为它会起作用,但它会考虑每两个数字(12 + 20 = 20 + 12)。从i开始,效率更高。为什么从1开始并不好?因为你可以解决方案:在我的例子中24 = 12 + 12。
  • 关于包含除数部分的for循环,您可以使用包含sqrt的方法,因为它更有效(O(sqrt(n))而不是O(n)) ,但你必须调整它。在我的示例中,您可以看到我有<= squareRoot,因为如果我不使用=,它会跳过一些值(例如:6是36的除数,但你不是将其包含在您的解决方案中)。因为我计算了6两次,所以我删除了其中一个根。当然,泰德的方法很好,但有时候提高性能会更好,即使简单性受到影响。