Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Diese Lerneinheit wurde für typische Bachelor-Klausuren konzipiert. So prüfen wir · Fehler entdeckt? Melde ihn uns oder markiere die fragliche Stelle direkt im Text oben.
Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Du sollst die 30. Fibonacci-Zahl berechnen. Naiver Code: 1,3 Millionen rekursive Aufrufe. Mit dynamischer Programmierung: 30 Aufrufe. Das ist die Macht von DP — du speicherst Zwischenergebnisse, damit du sie nicht doppelt berechnest. Klausur-Pflicht in 14/17 WInf-Algo-Klausuren, eines der mächtigsten algorithmischen Konzepte überhaupt.
Klausur-Tipp: Bei DP-Aufgaben IMMER zuerst die Rekurrenz aufschreiben ( + Basis-Fall). Dann eine Tabelle anlegen und die ersten Werte explizit ausrechnen. Punkteklau-sicher in Klausuren.
Anmelden, um den Fortschritt zu speichern.
Nächster Schritt
Aktives Abrufen festigt Wissen schneller als nochmal lesen.
Du sollst die 30. Fibonacci-Zahl berechnen. Naiver Code: 1,3 Millionen rekursive Aufrufe. Mit dynamischer Programmierung: 30 Aufrufe. Das ist die Macht von DP — du speicherst Zwischenergebnisse, damit du sie nicht doppelt berechnest. Klausur-Pflicht in 14/17 WInf-Algo-Klausuren, eines der mächtigsten algorithmischen Konzepte überhaupt.
Dynamische Programmierung (DP): Zerlege ein Problem in überlappende Teilprobleme, löse jedes Teilproblem nur einmal und speichere das Ergebnis. Setze die Teilergebnisse zu einer Gesamtlösung zusammen.
Ein Problem ist DP-fähig, wenn es zwei Eigenschaften hat:
Wenn nur (1) gilt, ohne (2), reicht Divide-and-Conquer (z.B. Mergesort). DP brauchst du genau wenn Teilprobleme sich wiederholen.
Naiv (exponentiell):
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
fib(5) ruft fib(4) und fib(3). fib(4) ruft fib(3) und fib(2). fib(3) wird also doppelt berechnet — und exponentiell oft bei größeren n. Laufzeit: O(2ⁿ).
Mit DP (Memoization, Top-Down):
int[] memo = new int[n + 1];
int fib(int n) {
if (n <= 1) return n;
if (memo[n] != 0) return memo[n];
memo[n] = fib(n - 1) + fib(n - 2);
return memo[n];
}
Jedes fib(k) wird nur einmal berechnet. Laufzeit: O(n).
Mit DP (Tabulation, Bottom-Up):
int fib(int n) {
if (n <= 1) return n;
int[] dp = new int[n + 1];
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
Beide DP-Varianten sind O(n). Bottom-Up spart den Rekursions-Overhead.
Rekursive Lösung, aber jedes Ergebnis wird in einer Tabelle gespeichert. Beim zweiten Aufruf direkt zurück.
Pro: Natürliche Übersetzung der Rekursion. Du berechnest nur was wirklich gebraucht wird. Contra: Rekursions-Overhead (Stack). Bei sehr großen n: Stack-Overflow.
Iterativ. Du baust die Tabelle von den kleinsten Teilproblemen hoch.
Pro: Kein Stack-Overhead. Oft schneller in der Praxis. Contra: Du musst die Reihenfolge kennen. Berechnet manchmal mehr als nötig.
Gegeben n Gegenstände mit Gewicht w_i und Wert v_i, ein Rucksack mit Kapazität W. Maximiere den Gesamtwert.
DP-Tabelle: dp[i][c] = max. Wert mit ersten i Items und Kapazität c.
dp[i][c] = max(dp[i-1][c], dp[i-1][c - w_i] + v_i)
Laufzeit: O(n · W). Pseudo-polynomial (W ist die Zahl, nicht log W).
Gegeben zwei Strings. Finde die längste Teilfolge, die in beiden vorkommt.
dp[i][j] = dp[i-1][j-1] + 1 wenn wenn s_i = t_j; max(dp[i-1][j], dp[i][j-1]) wenn sonst
Laufzeit: O(m · n).
Wie viele Operationen (Insert/Delete/Replace) braucht man, um String A in String B zu verwandeln?
Standard-DP-Anwendung, O(m · n).
Gegeben Münz-Werte \c₁, c₂, ..., c_n\ und Zielbetrag S. Minimiere die Anzahl Münzen.
dp[s] = min_(c_i ≤ s) (dp[s - c_i] + 1)
O(n²) naiv, O(n log n) mit Binary Search.
Greedy: trifft lokal beste Entscheidung, ohne zurückzuschauen. Schnell, aber findet manchmal nicht das Optimum.
DP: prüft alle relevanten Optionen, garantiert das Optimum.
Beispiel: Münzwechsel mit Münzen \1, 5, 10, 25\ für 30 Cent.
Aber bei \1, 6, 10\ für 12 Cent:
Greedy ist nicht immer optimal — DP ist es.
1. Überlappende Teilprobleme + optimale Substruktur → DP geeignet.
2. Memoization für rekursive Lösungen, Tabulation für iterative. Wenn beides geht, ist Bottom-Up oft schneller.
3. DP-Tabelle aufzeichnen. Bei Klausur-Aufgaben hilft eine explizite Tabelle (Zeilen = i, Spalten = j) — Punkteklau-frei.
4. Rekurrenz hinschreiben + Basis-Fall. Standard-Klausur-Form: dp[i] = ... + dp[0] = ....
5. Komplexität = Anzahl Zustände × Aufwand pro Übergang. Rucksack: O(n · W), LCS: O(m · n).
1. Memoization vergessen. Wer "DP" macht aber die Memo-Tabelle nicht checkt, hat einfach nur eine teure Rekursion.
2. Falsche Reihenfolge bei Tabulation. dp[i] braucht dp[i-1] und dp[i-2] → musst aufsteigend befüllen. Bei 2D-Tabellen: Reihenfolge der Schleifen wichtig.
3. Basis-Fälle falsch. dp[0] und dp[1] explizit setzen, sonst Müll in der Tabelle.
4. Rucksack als 1D-Array. 2D-Tabelle ist klassisch, 1D-Optimierung möglich aber gefährlich (richtung der Schleife muss umgekehrt sein, um Doppel-Zählung zu vermeiden).
5. DP für nicht-DP-Probleme. Wenn keine überlappenden Teilprobleme: Divide-and-Conquer reicht (z.B. Mergesort, Binäre Suche). DP wäre Overkill.
Geh Schritt für Schritt durch die Fibonacci-DP-Tabelle und sieh, wie sie sich aufbaut:
Beobachte: bei naiver Rekursion explodieren die Aufrufe, bei DP wächst die Tabelle linear.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Bei DP-Aufgaben IMMER zuerst die Rekurrenz aufschreiben (dp[i] = ... + Basis-Fall). Dann eine Tabelle anlegen und die ersten Werte explizit ausrechnen. Punkteklau-sicher in Klausuren.
6 Aufgaben zu DP-Konzepten, Memoization, Tabulation, klassischen Problemen.
Klausurfragen mit Lösungen (6)
Antwort: Optimale Substruktur UND überlappende Teilprobleme
Erklärung: BEIDES nötig: (1) Optimum aus Teil-Optima zusammenbaubar, (2) Teilprobleme tauchen mehrfach auf. Nur (1) ohne (2) → Divide-and-Conquer reicht. Greedy ist ein anderes Paradigma.
Antwort: O(2ⁿ) (exponentiell)
Erklärung: Naive Rekursion fib(n) = fib(n-1) + fib(n-2) verzweigt sich → O(2ⁿ). fib(30) braucht ca. 1,3 Mio Aufrufe. Mit DP (Memoization oder Tabulation): O(n).
Antwort: Wahr
Erklärung: RICHTIG. Memoization: rekursiv von oben (Problem → Teilprobleme), Ergebnisse in Tabelle speichern. Tabulation: iterativ von unten (kleinste Teilprobleme zuerst), Tabelle iterativ befüllen.
Typ: Wahr/Falsch
Antwort: Binäre Suche
Erklärung: Binäre Suche ist Divide-and-Conquer, NICHT DP — keine überlappenden Teilprobleme, jeder Schritt halbiert das Problem in nur ein Teilproblem. Rucksack, LCS, Edit-Distanz sind DP-Klassiker.
Richtige Antworten: Memoization spart Berechnungen durch Caching; Tabulation berechnet manchmal mehr Werte als nötig; DP findet immer das Optimum (bei korrekter Rekurrenz); Knapsack hat Laufzeit O(n · W)
Erklärung: Richtig: Memoization = Caching, Tabulation überberechnet manchmal, DP = optimal, Knapsack pseudo-polynomial O(n·W). Falsch: DP kann rekursiv (Memoization) oder iterativ (Tabulation) sein; Greedy ist schneller ABER findet nicht immer das Optimum.
Typ: Multi-Select
Zuordnungen:
Erklärung: Standard-Laufzeiten. Fibonacci: linear. Knapsack: pseudo-polynomial. LCS: quadratisch. Naive: exponentiell.
Typ: Zuordnung
Klausurfragen mit Lösungen (6)
Antwort: Die Laufzeit ist polynomial im Wert W, nicht in log(W)
Erklärung: Eingabe-Länge einer Zahl W ist log(W) Bits. Polynomial in der Eingabe-Länge wäre O(n · log W). Knapsack ist O(n · W) — das W wird als Zahl gezählt, nicht als Bits → 'pseudo'-polynomial. Bei sehr großen W wird's langsam.
Antwort: Falsch
Erklärung: FALSCH. Greedy macht lokal beste Entscheidungen → optimal NUR bei Problemen mit Greedy-Auswahl-Eigenschaft (z.B. Münzwechsel mit 1/5/10/25). Bei Münzen {1, 6, 10} und Ziel 12: Greedy=3 Münzen (10+1+1), DP=2 Münzen (6+6). DP ist garantiert optimal.
Typ: Wahr/Falsch
Antwort: Maximaler Wert mit ersten i Items und Kapazität c
Erklärung: dp[i][c] = MAXIMALER WERT, den man mit den ersten i Items und einer Kapazität von c erreichen kann. Rekurrenz: dp[i][c] = max(dp[i-1][c], dp[i-1][c-w_i] + v_i). Erste Option: Item i nicht nehmen. Zweite: nehmen.
Antwort: Wenn nur wenige Teilprobleme tatsächlich gebraucht werden
Erklärung: Memoization berechnet nur Teilprobleme die WIRKLICH gebraucht werden (lazy). Tabulation berechnet alle systematisch. Wenn die meisten Teilprobleme nicht relevant sind, ist Memoization deutlich schneller.
Lösungen pro Lücke:
Erklärung: Standard-Vokabular DP. Voraussetzungen + zwei Stile + Beispiel-Laufzeit-Verbesserung von 2ⁿ auf n.
Typ: Lückentext
Richtige Reihenfolge:
Erklärung: Standard-Klausur-Workflow für DP-Aufgaben. Teilprobleme → Rekurrenz → Basis → Stil wählen → befüllen → Antwort.
Typ: Reihenfolge