Project Euler#12的Java代码

时间:2013-08-16 20:52:44

标签: java

我正在研究Project Euler的问题#12,其内容如下:

  

通过添加自然数来生成三角数的序列。所以第7个三角形数字是1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.前十个术语是:

     

1,3,6,10,15,21,28,36,45,55,......

     

让我们列出前七个三角形数字的因子:

     

1:1

     

3:1,3

     

6:1,2,3,6

     

10:1,2,5,10

     15:1,3,5,15

     

21:1,3,7,21

     

28:1,2,4,7,14,28

     

我们可以看到28是第一个超过五个除数的三角形数。

     

第一个三角形数的值超过500个除数是多少?

这是我到目前为止的代码,但是控制台在运行时不会返回任何内容:

public class Euler12 {
    public static void main (String[] args) {
        int i = 1;
        int x = 2;
        boolean found = false;
        while (!found) {
            if (divisors(i) > 500) {
                System.out.println(i);
                found = true;
            }
            else {
                i +=x;
                x++;
            }
        }
    }

    public static int divisors (int n) {
        int counter = 0;
        for (int i = 1; i <= n; i++) {
            if (n % i == 0) counter++;
        }
        return counter;
    }
}

4 个答案:

答案 0 :(得分:2)

运行程序后,似乎它的运行时间非常长,看着你的算法,它确实(我以前做过这个问题)。你需要优化“除数”

<强> SPOILER

如果将(int i = 1; i&lt; = n; i ++)更改为for(int i = 1; i * i&lt; = n; i ++),则会大大减少执行时间。

更新: 在没有改变的情况下运行后,在4分钟内没有答案,这违反了Project Euler的一分钟规则。改变后,在十秒钟内得到答案。享受:)

答案 1 :(得分:1)

public class EulerProb12 {

    public static void main(String[] args) {

        int fib=0, count =1, i=1, incr=0;

        while (incr<5){         
            fib=0;
            while (i<=count){       
                fib = fib+i;
                i++;
            }

             i=1;
            incr=0;
            count++;

            for(int j=1; j<= Math.sqrt(fib); j++ ) // I used fib/2 here n result came late.
            {
                if(fib%j==0)
                {
                    incr++;
                }
            }
            incr*=2; // New logic when implemented along with sqrt
//          if(incr>150)
            System.out.println("Number: " + fib + " | Total Divisors: " + incr);        }
        System.out.println("Number: " + fib + " | Total Divisors: " + incr);
    }

}

答案 2 :(得分:1)

以下是两种选择:

1)迭代所有三角形,如果currentSum(三角形数字)超过THRESHOLD除数则停止
时间:1.79秒

public class P12 {

    final static int THRESHOLD = 500;

    public static void main(String[] args) {
        System.out.println(getTriangle());
    }

    public static long getTriangle() {
        int n = 1;
        long currentSum = 0;
        while (!hasOverXDivisors(currentSum, THRESHOLD)) {
            currentSum += n;
            n++;
        }
        return currentSum;
    }

    private static boolean hasOverXDivisors(long nr, int threshold) {
        if ( nr <= threshold ) {
            return false;
        }
        int divisors = 0;
        int i;
        int sqrt = (int) Math.sqrt(nr);
        for ( i = 1 ; i <= sqrt ; i++ ) {
            if ( nr % i == 0 ) {
                divisors+=2;           // E.g.: (2, n/2), (3, n/3)
            }
        }
        if ( sqrt*sqrt == nr ){        // it was counted twice
            divisors--;
        }
        if ( divisors > threshold ) {
            return true;
        }
        return false;
    }

}

2)它基于互质数字属性。三角形数等于n*(n+1)/2,其中nn+1是互质= = n(n+1)/2是互质,n/2n+1是互质(取决于n是偶数还是奇数)。
时间:61毫秒

public class P12 {

    final static int THRESHOLD_DIVISORS = 500;    

    public static void main(String[] args) {
        System.out.println(getTriangle(1));
    }

    public static long getTriangle(int n) {
        long numberOfDivisors = 0;
        long firstCoprime, secondCoprime;
        while (true) {
            if ( n % 2 == 0 ) {
                firstCoprime = getNumberOfDivisors(n/2);
                secondCoprime = getNumberOfDivisors(n+1);

            } else {
                firstCoprime = getNumberOfDivisors(n);
                secondCoprime = getNumberOfDivisors((n+1)/2);
            }           
            numberOfDivisors = firstCoprime * secondCoprime;
            if ( numberOfDivisors > THRESHOLD_DIVISORS ) {
                return n*(n+1)/2;
            }       
            n++;
        }
    }

    private static long getNumberOfDivisors(long nr) {
        int divisors = 0;
        int i;
        int sqrt = (int) Math.sqrt(nr);
        for ( i = 1 ; i <= sqrt ; i++ ) {
            if ( nr % i == 0 ) {
                divisors+=2;           // E.g.: (2, n/2), (3, n/3)
            }
        }
        if ( sqrt*sqrt == nr ){        // it was counted twice
            divisors--;
        }
        return divisors;
    }

}

我使用整数作为getTriangle()方法的参数来更容易地改进此方法。对于此特定情况,您可以决定从大于1的值开始。在这种情况下,您可以将时间减少至少3次。

答案 3 :(得分:0)

使用“素数因子分解”将使您的divisor()更快更好。

尝试使用以下功能getNumberOfDivisors(),而不是divisor()

public static long getNumberOfDivisors (long n) {
    int ret = 1;

    long factor = 2;
    while (factor <= n) {
        int temp = 1;
        while (n % factor == 0) {
            n /= factor;
            temp++;
        }
        ret *= temp;
        factor++;
    }

    return ret;
}

该函数的工作原理如下:

如果n = p 1 e1 p 2 e2 ... p n en ,其中n是一个整数,p i :primes,

然后,

正向除数:( e 1 + 1)(e 2 + 1)...(e n + 1)