Java 8: 1.8e8 2.4e8
Dieser Eintrag ist nicht mit einigen anderen Einträgen vergleichbar, aber ich wollte meine Antwort posten, da es mir Spaß gemacht hat, daran zu arbeiten.
Die Hauptoptimierungen meines Ansatzes sind wie folgt:
- Jede gerade Zahl hat den kleinsten Faktor 2, sodass diese nach jeder ungeraden Zahl kostenlos hinzugefügt werden können. Grundsätzlich, wenn Sie die Arbeit gemacht haben, um zu berechnen,
T(N)
wann N % 2 == 1
, wissen Sie das T(N + 1) == T(N) + 2
. Dies ermöglicht es mir, mit dem Zählen um drei zu beginnen und durch Iteration um zwei zu erhöhen.
- Ich speichere meine Primzahlen in einem Array im Gegensatz zu einem
Collection
Typ. Das hat sich mehr als verdoppelt, als N
ich erreichen kann.
- Ich verwende die Primzahlen, um eine Zahl zu faktorisieren, anstatt das Sieb des Eratosthenes durchzuführen. Dies bedeutet, dass mein Speicher fast vollständig auf mein Primes-Array beschränkt ist.
- Ich speichere die Quadratwurzel der Zahl, für die ich den kleinsten Faktor zu finden versuche. Ich habe versucht, bei @ user1354678 jedes Mal einen Primfaktor zu quadrieren, aber das hat mich ungefähr 1e7 von meiner Punktzahl gekostet.
Das ist ungefähr alles, was es zu tun gibt. Mein Code iteriert ab 3 zu zweit, bis er feststellt, dass er das Zeitlimit erreicht oder überschritten hat. Zu diesem Zeitpunkt gibt er die Antwort aus.
package sum_of_smallest_factors;
public final class SumOfSmallestFactors {
private static class Result {
private final int number;
int getNumber() {
return number;
}
private final long sum;
long getSum() {
return sum;
}
Result(int number, long sum) {
this.number = number;
this.sum = sum;
}
}
private static final long TIME_LIMIT = 60_000_000_000L; // 60 seconds x 1e9 nanoseconds / second
public static void main(String[] args) {
SumOfSmallestFactors main = new SumOfSmallestFactors();
Result result = main.run();
int number = result.getNumber();
long sum = result.getSum();
System.out.format("T(%,d) = %,d\n", number, sum);
}
private int[] primes = new int[16_777_216];
private int primeCount = 0;
private long startTime;
private SumOfSmallestFactors() {}
private Result run() {
startClock();
int number;
long sumOfSmallestFactors = 2;
for (number = 3; mayContinue(); number += 2) {
int smallestFactor = getSmallestFactor(number);
if (smallestFactor == number) {
addPrime(number);
}
sumOfSmallestFactors += smallestFactor + 2;
}
--number;
Result result = new Result(number, sumOfSmallestFactors);
return result;
}
private void startClock() {
startTime = System.nanoTime();
}
private boolean mayContinue() {
long currentTime = System.nanoTime();
long elapsedTime = currentTime - startTime;
boolean result = (elapsedTime < TIME_LIMIT);
return result;
}
private int getSmallestFactor(int number) {
int smallestFactor = number;
int squareRoot = (int) Math.ceil(Math.sqrt(number));
int index;
int prime = 3;
for (index = 0; index < primeCount; ++index) {
prime = primes[index];
if (prime > squareRoot) {
break;
}
int remainder = number % prime;
if (remainder == 0) {
smallestFactor = prime;
break;
}
}
return smallestFactor;
}
private void addPrime(int prime) {
primes[primeCount] = prime;
++primeCount;
}
}
Das Ausführen auf einem anderen System (Windows 8.1, Intel Core i7 bei 2,5 GHz, 8 GB RAM) mit der neuesten Version von Java 8 führt zu deutlich besseren Ergebnissen ohne Codeänderungen:
T(240,308,208) = 1,537,216,753,010,879