减少代码的运行时间

时间:2011-06-05 19:38:53

标签: java

如何让这段代码更快地运行?

public class ProjectEuler3 {
    public static void main(String[] args) {
        System.out.println(findfactors(600851475143l));
    }

    public static long findfactors(long n) {
        long[] factors = new long[1000000];
        int nooffactor = 0;

        int c = 0;

        for (long i = 2; i < n; i++) {
            if (findPrime(i)) {
                factors[c++] = i;
                nooffactor++;
            }
        }

        return factors[nooffactor - 1];
    }

    public static boolean findPrime(long n) {
        for (long i = 2; i < n; i++) {
            if(n % i == 0)
                return false;
        }
        return true;
    }
}

6 个答案:

答案 0 :(得分:6)

我不确定这个特殊问题的要求,但一个性能提升将是改善你的primality test。现在,你正在检查从2到n。但是,您只需要检查2到sqrt(n),这将大大减少当n是大数时检查的数字。您也无法检查大于2的偶数值。

它仍然很简单,但这会带来性能提升,特别是对于较大的n:

public static boolean findPrime(long n){
    int max = (int) Math.ceil(Math.sqrt(n))
    for(long i=2; i<max; i++){
        if(n%i == 0) {
            return false;
        }
    }
    return true;
}

尽管可能会有更好的解决方案,例如完全不同的问题解决方法(参见Matt Ball's suggestion of a totally different factoring algorithm),具体取决于您要做的事情。我只是在查看您的代码,并试图在没有重大策略变化的情况下减少操作数量。

答案 1 :(得分:3)

在计算完素数时考虑记住素数。

答案 2 :(得分:2)

通过研究分解算法。

答案 3 :(得分:0)

如果两个是一个因素,那么你可以继续将n除以2,直到它不可分割为止。这也适用于其他数字。这大大减少了循环的长度。

预先计算所有素数到sqrt(n)也会有所帮助。

答案 4 :(得分:0)

实际上,要注意的关键是你不需要一直到原来的股息。当您找到一个因子时,您将红利除以该因子(根据需要多次),然后增加除数。只要这个数字没有出现一些巨大的主要因素(不太可能),这将是非常快的。

从技术上讲,你只需要搜索到平方根,但是为了你的目的,如果按照我上面说的那样做,它将没有多大区别。

这是Scala实现:

  def lpf(n: Long, f: Long): Long = {    // Largest prime factor function, n = dividend, f = trial divisor
    if (f * f > n) n                     // If divisor squared is bigger than dividend, we have the answer
    else if (n % f == 0) lpf(n / f, f)   // If it divides exactly, divide through and try again with same factor
    else lpf(n, f + 1)                   // Otherwise increase divisor
  }
  println(lpf(600851475143L, 2))         // Completes in 1.6 milliseconds

答案 5 :(得分:0)

你可以尝试这样的事情。

private static final BitSet IS_PRIME = new BitSet(); static {
    IS_PRIME.set(2);
}

private static int IS_PRIME_LIMIT = 2;

public static boolean isPrime(int n) {
    int p = IS_PRIME_LIMIT;
    while (p < n) {
        p++;
        IS_PRIME.set(p);
        if (p % 2 == 0) {
            IS_PRIME.clear(p);
        } else {
            for (int i = 3; i * i <= p; i += 2)
                if (IS_PRIME.get(i) && p % i == 0) {
                    IS_PRIME.clear(p);
                    break;
                }
        }
    }
    IS_PRIME_LIMIT = p;
    return IS_PRIME.get(n);
}

public static List<Integer> findfactors(long n) {
    List<Integer> ret = new ArrayList<Integer>();
    int sqrtN = (int) Math.sqrt(n);

    for (int i = 2; n > 1 && i <= sqrtN; i++) {
        if (isPrime(i)) {
            while (n > 1 && n % i == 0) {
                n /= i;
                ret.add(i);
            }
        }
    }
    if (n > 1)
        ret.add((int) n);
    return ret;
}

public static void main(String... args) {
    // warm up
    for(int i=0;i<10000;i++)
        findfactors(600851475143L);

    //  time one lookup.
    long start = System.nanoTime();
    List<Integer> factors = findfactors(600851475143L);
    long time = System.nanoTime() - start;
    System.out.println(factors);
    System.out.printf("Took %.3f ms to find factors%n", time/1e6);
}

打印

[71, 839, 1471, 6857]
Took 0.051 ms to find factors