2016-10-11 5 views
5

Ich versuche gerade eine ProjectEuler problem zu lösen und ich habe alles außer der Geschwindigkeit runter. Ich bin fast sicher, der Grund, warum das Programm so langsam ausgeführt wird, liegt an den verschachtelten Schleifen. Ich würde gerne Ratschläge bekommen, wie man das beschleunigen kann. Ich bin ein Anfänger Programmierer, so dass ich nicht mit vielen der fortgeschrittenen Methoden/Themen vertraut bin.Wie würde ich dieses Programm beschleunigen?

public class Problem12 { 

    public static void main(String[] args) { 
     int num; 

     for (int i = 1; i < 15000; i++) { 
      num = i * (i + 1)/2; 
      int counter = 0; 

      for (int x = 1; x <= num; x++) { 
       if (num % x == 0) { 
        counter++; 
       } 
      } 
      System.out.println("[" + i + "] - " + num + " is divisible by " + counter + " numbers."); 
     } 
    } 
} 

EDIT: Unten ist der neue Code, der exponentiell schneller ist. Der Druck der konstanten Linie wurde ebenfalls entfernt, um die Geschwindigkeit noch zu erhöhen.

public class Problem12 { 

    public static void main(String[] args) { 
     int num; 

     outerloop: 
     for (int i = 1; i < 25000; i++) { 
      num = i * (i + 1)/2; 
      int counter = 0; 

      double root = Math.sqrt(num); 
      for (int x = 1; x < root; x++) { 
       if (num % x == 0) { 
        counter += 2; 
        if (counter >= 500) { 
         System.out.println("[" + i + "] - " + num + " is divisible by " + counter + " numbers."); 
         break outerloop; 
        } 
       } 
      } 
     } 
    } 
} 
+1

Versuchen Sie, eine schnellere Sprache wie C verwenden und versuchen bitshifts statt Divisionen und Multiplikationen verwenden, wenn sie überhaupt in Java –

+0

Ist dieser Algorithmus Arbeit verfügbar sind? Also wie wenn 'i = 3' dann' num = 6' und dann 'counter = 4' was falsch ist – afsafzal

+4

@ShaheAnsar Wie kannst du davon ausgehen, dass C schneller ist als Java für diesen Fall, wenn du nicht genug weißt um es zu wissen Bitshifts werden unterstützt? – njzk2

Antwort

5

Für den Anfang, wenn bei Teilern suchen, müssen Sie nie weiter als die Quadratwurzel der Anzahl gehen, weil jeder Divisor unter der Quadratwurzel über eine äquivalente hat.

n = a * b => a <= sqrt(n) or b <= sqrt(n) 

Dann müssen Sie die andere Seite der Division zählen:

double root = Math.sqrt(num); 
for (int x = 1; x < root; x++) { 
    if (num % x == 0) { 
     counter += 2; 
    } 
} 

Die Quadratwurzel ist etwas Besonderes, weil es nur einmal zählt, wenn es ganze Zahl ist:

if ((double) ((int) root) == root) { 
    counter += 1; 
} 
+0

Dies hat den Trick. Ich bin mir jedoch nicht sicher wie. Würde es Ihnen etwas ausmachen, mehr darüber zu erfahren, warum das funktioniert? – jxshu

+1

jeder Teiler arbeitet als ein Paar, weshalb wir jedes zweimal zählen. Für jedes Paar befindet sich eines der Elemente unterhalb der Quadratwurzel, das andere oberhalb. Das ist leicht zu sehen: Wenn beide Elemente oben sind, ist das Ergebnis ebenfalls oben. Wenn beide unten sind, ist das Ergebnis auch darunter. Beispiel: '10 = 2 * 5 = 1 * 10'. 2 und 1 sind unter 3.16, 5 und 10 sind oben. – njzk2

+0

Ich habe mich auch geirrt, dass es keine dreieckigen und quadratischen Zahlen gibt, die jetzt bearbeitet werden – njzk2

0

Sie haben soeben muss die Nummer faktorisieren. p^a * q^b * r^c hat (a+1)*(b+1)*(c+1) Teiler. Hier finden Sie einige grundlegende Implementierung mit dieser Idee:

static int Divisors(int num) { 
    if (num == 1) { 
     return 1; 
    } 

    int root = (int) Math.sqrt(num); 
    for (int x = 2; x <= root; x++) { 
     if (num % x == 0) { 
      int c = 0; 
      do { 
       ++c; 
       num /= x; 
      } while (num % x == 0); 
      return (c + 1) * Divisors(num); 
     } 
    } 

    return 2; 
} 

public static void test500() { 
    int i = 1, num = 1; 
    while (Divisors(num) <= 500) { 
     num += ++i; 
    } 

    System.out.println("\nFound: [" + i + "] - " + num); 
} 
Verwandte Themen