====== Day 11: Plutonian Pebbles ====== Dieser Tag ist etwas kniffliger. Teil 1 kann man noch zur **mittleren Schwierigkeit** zählen, Teil 2 hingegen zählt definitiv zur **höchsten Schwierigkeitsstufe**, da man **Memoisation bzw. dynamische Programmierung** benötigt. Das bedeutet, dass man Zwischenergebnisse speichern muss, um bei erneuten rekursiven Aufrufen mit denselben Parametern direkt das vorherige Ergebnis zurückliefern zu können. Andernfalls würde die Rechenzeit für Teil 2 explodieren. Hierzu wird eine **HashMap** benötigt. ===== Teil 1 ===== Teil 1 lässt sich noch relativ //straight-forward// lösen. Man speichert die Input-Zahlen also in einer ArrayList und iteriert 25x über die Schleife. Pro Iteration erstellt man am besten eine **neue** ArrayList, die man mit den neuen Werten füllt, die sich nach den Regeln aus der **alten** ArrayList (des letzten Durchgangs) ergeben. ++++ Lösungsvorschlag | public void partOne() { // Übertrage die Input-String-Zahlen in ein Array ArrayList input = new ArrayList(); for (String n: inputLines.get(0).split(" ")) { input.add(Long.parseLong(n)); } // 25x "blinzeln" for (int blink = 0; blink < 25; blink++) { // erstelle pro Durchgang eine neue ArrayList für die neuen Werte ArrayList next = new ArrayList(); // pro altem Wert des letzten Durchgangs for (long i: input) { if (i == 0) { next.add((long)1); } else if (String.valueOf(i).length() % 2 == 0) { // Aufteilung in vordere/hintere Hälfte der Zahl next.add((long) (i / Math.pow(10,(String.valueOf(i).length()/2)))); next.add((long) (i % Math.pow(10,(String.valueOf(i).length()/2)))); } else { next.add(i * 2024); } } // mache die aktuelle/neue ArrayList "next" zur alten für den nächsten Durchlauf input = next; } System.out.println(input.size()); } ++++ ===== Teil 2 ===== Eine ausführliche Erklärung würde hier vermutlich den Rahmen sprengen. Der Quellcode des Lösungsvorschlags ist ein wenig kommentiert... ++++ Lösungsvorschlag | public void partTwo() { // Speichert pro "Steinzahl" ein Array, das wiederum pro Zeitschritt 0-74 die bereits // errechneten Ergebnisse (Anzahl der Steine bei Zeitschritt 75) speichert. memo = new HashMap(); // Übertrage die Input-String-Zahlen in ein Array ArrayList input = new ArrayList(); for (String n: inputLines.get(0).split(" ")) { input.add(Long.parseLong(n)); } // Starte pro Input-Zahl den rekursiven Aufruf long stones = 0; for (long i: input) { stones += calculate(i, 0); } System.out.println(stones); } private long calculate(long i, int times) { // Letzter Zeitschritt? Dann gibts genau einen (weiteren) Stein if (times == 75) { return 1; } // Schaue im Speicher der Zwischenergebnisse nach, ob schon einmal die Anzahl der Steine // beim Input i zum Zeitpunkt times berechnet wurde. long[] stones = memo.get(i); if (stones != null && stones[times] != 0) { return stones[times]; } else if (stones == null) { // Wenn zu dieser Zahl noch nie nachgeschaut wurde, dann erstelle schon mal das leere Array für die verschiedenen Zeitpunkte stones = new long[75]; } long result = 0; if (i == 0) { result += calculate((long)1,times+1); } else if (String.valueOf(i).length() % 2 == 0) { result += calculate((long) (i / Math.pow(10,(String.valueOf(i).length()/2))), times+1); result += calculate((long) (i % Math.pow(10,(String.valueOf(i).length()/2))), times+1); } else { result += calculate(i * 2024,times+1); } // Speichere das neue Ergebnis für den Zeitpunkt times stones[times] = result; // speichere das ganze Array der verschiedenen Zeitpunkte in der HashMap passend zum Wert i memo.put(i, stones); return result; } ++++