Memoization (zapamiętywanie wyników)
1. Czym jest memoization?
Memoization to technika optymalizacji polegająca na zapamiętywaniu wyników funkcji, aby uniknąć ponownych obliczeń dla tych samych argumentów.
1.1. Nazwa:
"Memoization" pochodzi od łacińskiego "memorandum" (do zapamiętania)
NIE "memorization"!
1.2. Zasada działania:
2. Implementacja ręczna - słownik
2.1. Fibonacci z cache:
Złożoność: - Czasowa: O(n) ✅ (każde fib(i) obliczane tylko raz) - Pamięciowa: O(n) – cache + stos rekurencji
3. Python @lru_cache decorator
3.1. Wbudowane narzędzie:
Zalety @lru_cache: - ✅ Automatyczne cachowanie - ✅ Thread-safe - ✅ Statystyki (hits, misses) - ✅ Czyszczenie cache (cache_clear())
3.2. LRU (Least Recently Used):
4. Przykład: Schody z różnymi krokami
4.1. Problem:
Wchodzisz po schodach o n stopniach.
Możesz wejść o 1, 2 lub 3 stopnie na raz.
Ile jest sposobów dotarcia na szczyt?
4.2. Rekurencja naiwna:
4.3. Z memoization:
5. Problem: Minimalna liczba monet (Coin Change)
5.1. Rekurencja z memoization:
5.2. Z @lru_cache:
6. Wizualizacja cache
6.1. Debug version:
Wynik:
fib(5) → obliczam...
fib(4) → obliczam...
fib(3) → obliczam...
fib(2) → obliczam...
fib(1) = 1 (bazowy)
fib(0) = 0 (bazowy)
fib(2) = 1
fib(1) → cache: 1
fib(3) = 2
fib(2) → cache: 1
fib(4) = 3
fib(3) → cache: 2
fib(5) = 5
7. Memoization dla funkcji z wieloma argumentami
7.1. Problem: Kombinacje z powtórzeniami:
7.2. Levenshtein distance (edit distance):
8. Benchmark: Rekurencja vs Memoization
9. Kiedy NIE używać memoization?
❌ Problem 1: Funkcje niedeterministyczne
❌ Problem 2: Funkcje z efektami ubocznymi
❌ Problem 3: Duże obiekty mutowalne
10. Czyszczenie cache
10.1. cache_clear():
10.2. Statystyki cache:
11. Własny decorator memoization
11.1. Prosty decorator:
11.2. Z funkcjonalnościami:
12. Podsumowanie
Memoization:
- Zapamiętywanie wyników funkcji
- Top-Down – rekurencja z cache
- Automatyczne – @lru_cache w Pythonie
- Transparentne – nie zmienia logiki funkcji
Zalety:
✅ Dramatyczne przyspieszenie (nawet 100,000x) ✅ Prosta implementacja (1 linia z @lru_cache) ✅ Zachowuje naturalną rekurencję ✅ Automatyczne cachowanie
Wady:
❌ O(n) pamięci dla cache ❌ O(n) pamięci dla stosu rekurencji ❌ Tylko dla funkcji "czystych" (pure functions) ❌ Problemy z mutowalnymi argumentami
Implementacje:
Złożoność:
| Problem | Naiwna rekurencja | Memoization |
|---|---|---|
| Fibonacci | O(2^n) ❌ | O(n) ✅ |
| Schody | O(3^n) ❌ | O(n) ✅ |
| Coin Change | O(2^n) ❌ | O(n×m) ✅ |
Kiedy używać:
✅ Funkcje "czyste" (bez efektów ubocznych) ✅ Drogie obliczenia ✅ Powtarzające się wywołania ✅ Naturalna rekurencja
Kiedy NIE używać:
❌ Funkcje niedeterministyczne (random) ❌ Efekty uboczne (I/O, modyfikacje) ❌ Mutowalne argumenty (listy) ❌ Pamięć jest krytyczna
@lru_cache parametry:
Statystyki:
Co dalej warto poznać:
- Tabulation – bottom-up DP (bez rekurencji)
- Space optimization – redukcja pamięci
- DP patterns – typowe wzorce problemów
- Advanced caching – Redis, Memcached
- Persistent memoization – cache na dysku