He escrito el siguiente código para descubrir el número de triángulo más pequeño que tiene más de 500 factores. ¿Cómo puedo hacerlo más eficiente?

Aquí hay un código que escribí en Java (se ejecuta en menos de 1 segundo con bucle ingenuo)

import java.util.HashSet;
import java.util.Set;
clase pública TriangleNumber {
Loops largos privados Run = 0;
/ **
* Devuelve la lista de factores de un número
* @param number
* /
public Set factorize (número largo) {
Establezca factorSet = new HashSet ();
// Poco mejor
largo hasta la mitad = 1 + (largo) Math.ceil (Math.sqrt (número));
for (long i = 1; i <halfway; i ++) {
loopsRun ++;
if (número% i == 0) {
// i y cociente son factores
factorSet.add (i);
factorSet.add (número / i);
}
}
factor de retorno
}
/ **
* Obtenga nTh número de triángulo, n = índice
* T (n) = n (n + 1) / 2
* @param index
* @regreso
* /
public long getTriangleNumber (índice largo) {
return (índice * (índice + 1)) / 2;
}
public long getLoopsRun () {
volver bucles Ejecutar;
}
Public Void Run (int limit) {
índice largo = 1;
largo startTime = System.nanoTime ();
número largo = getTriangleNumber (índice);
factores largos = factorizar (número). tamaño ();
while (factores <= límite) {
largo transcurrido = System.nanoTime () – startTime;
if (transcurrido> = 1_000_000_000) {
System.out.println (“ElapsedTime (ns):” + transcurrido
+ “: índice:” + índice + “número:” + número + “: factores:” + factores);
}
index ++;
número = getTriangleNumber (índice);
factores = factorizar (número). tamaño ();
}
long endTime = System.nanoTime ();
long elapsedTime = endTime – startTime;
System.out.println (“ElapsedTime (ns):” + elapsedTime + “loopsRun:” + getLoopsRun ()
+ “: índice:” + índice + “número:” + número + “: factores:” + factores);
}
public static void main (String [] args) {
TriangleNumber triangles = new TriangleNumber ();
triangles.run (500);
TriangleNumberBetter trianglePrime = new TriangleNumberBetter ();
trianglePrime.run (500);
}
}

Aquí está la salida

ElapsedTime (ns): 649489562 bucles Ejecución: 54158321: índice: 12375 número: 76576500: factores: 576

El primer número con más de 500 factores es 12.375º Triángulo.

EDITAR:

Aquí hay una mejor versión en Java (que usa la factorización de números primos para calcular directamente el número total de factores de un número dado)

importar java.util.HashMap;
import java.util.Map;
clase pública TriangleNumberBetter {
Loops largos privados Run = 0;
Mapa privado previousFactors = new HashMap ();
Mapa privado currentFactors = new HashMap ();
primos privados int [];
/ **
* Devuelve los factores totales utilizando factores de índice anteriores y actuales
* @regreso
* /
public int totalFactors () {
int total = 1;
Map totalFactors = new HashMap ();
totalFactors.putAll (previousFactors);
currentFactors.forEach ((k, v) -> {
valor int = v + totalFactors.getOrDefault (k, 0);
totalFactors.put (k, valor);
loopsRun ++;
});
// Dado que los factores totales de N (N + 1) / 2 tendrán 1 potencia menor de 2 que N * (N + 1)
if (totalFactors.get (2)! = null) {
totalFactors.put (2, totalFactors.get (2) -1);
}
for (Factores enteros: totalFactors.values ​​()) {
total * = (factores + 1);
loopsRun ++;
}
retorno total;
}
/ **
* Devuelve un mapa de factores primos de un número
* De forma A ^ a * B * b * C * c …
* Mapa donde A = número primo, a = exponente total
* @param number
* @regreso
* /
public Map primeFactorize (int número) {
Map primeFactors = new HashMap ();
if (número <2) {
return primeFactors;
}
largo hasta la mitad = 1 + (largo) Math.ceil (Math.sqrt (número));
for (int i = 0; i <primes.length && primes [i] <= halfway; i ++) {
int exponente = 0;
int divisor = primos [i];
while (número% divisor == 0) {
exponente ++;
divisor = divisor * primos [i];
loopsRun ++;
}
if (exponente> 0) {
primeFactors.put (primos [i], exponente);
}
loopsRun ++;
}
return primeFactors;
}
public void primeFactorizor (número int) {
previousFactors.clear ();
previousFactors.putAll (currentFactors);
currentFactors.clear ();
currentFactors.putAll (primeFactorize (número + 1));
}
/ **
* Devuelve los primeros N números primos
* @param total
* @regreso
* /
public void generatePrimeNumbers (int N) {
primos = nuevo int [N];
int primesSoFar = 0;
int número = 2;
while (primesSoFar <N) {
loopsRun ++;
if (isPrime (número)) {
primos [primesSoFar] = número;
primesSoFar ++;
}
número ++;
}
}
/ **
* Prueba si un número es primo
* @param total
* @regreso
* /
public boolean isPrime (int número) {
boolean isPrime = true;
largo hasta la mitad = 1 + (largo) Math.ceil (Math.sqrt (número));
para (largo i = 2; i <a mitad de camino; i ++) {
loopsRun ++;
if (número% i == 0 && número! = i) {
isPrime = false;
descanso;
}
}
return isPrime;
}
/ **
* Obtenga nTh número de triángulo, n = índice
* T (n) = n (n + 1) / 2
* @param index
* @regreso
* /
public long getTriangleNumber (índice largo) {
return (índice * (índice + 1)) / 2;
}
public long getLoopsRun () {
volver bucles Ejecutar;
}
Public Void Run (int limit) {
largo startTime = System.nanoTime ();
generatePrimeNumbers (1000);

int index = 1;
número largo = getTriangleNumber (índice);
factores largos = totalFactors ();
while (factores <= límite) {
largo transcurrido = System.nanoTime () – startTime;
if (transcurrido> = 1_000_000_000) {
System.out.println (“ElapsedTime (ns):” + elapsed + “loopsRun:” + getLoopsRun ()
+ “: índice:” + índice + “número:” + número + “: factores:” + factores);
}
index ++;
primeFactorizor (índice);
factores = totalFactors ();
número = getTriangleNumber (índice);
}
long endTime = System.nanoTime ();
long elapsedTime = endTime – startTime;
System.out.println (“ElapsedTime (ns):” + elapsedTime + “loopsRun:” + getLoopsRun ()
+ “: índice:” + índice + “número:” + número + “: factores:” + factores);
}
}

Este código se ejecuta en

ElapsedTime (ns): 93246660 bucles Ejecución: 444496: índice: 12375 número: 76576500: factores: 576

El número de bucles es ~ 120 veces menos y el tiempo total empleado es de aproximadamente 93 ms (aproximadamente 7 veces menos que ~ 650 ms)

EDITAR FIN

Su ciclo se ejecuta solo hasta 10,000

Además, mi código se puede optimizar aún más al memorizar los subfactores (que estoy calculando una y otra vez para cada número)

Y aquí hay un código de Python

matemáticas de importación
def factorizar (número):
factores = {}
halfway = 1 + int (math.ceil (math.sqrt (number)))
para i en rango (1, a medio camino):
if (número% i == 0):
factores [i] = verdadero
factores [número / i] = verdadero

factores de retorno

def getTriangleNumber (número):
return (número * (número + 1)) / 2

if __name__ == “__main__”:
índice = 1
número = getTriangleNumber (índice)
factores = len (factorizar (número))
mientras que los factores <= 500:
índice + = 1
número = getTriangleNumber (índice)
factores = len (factorizar (número))

imprimir “Índice:% d, Número% d, Factores:% d”% (índice, número, factores)

que se ejecuta en unos 4 segundos

time python ~ / Desktop / triangleNumber.py
Índice: 12375, número 76576500, factores: 576
0m3.873s reales
usuario 0m3.776s
sys 0m0.045s