如何让这段代码更快地运行?
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;
}
}
答案 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