"메모이제이션은 동적 계획법으로 가는 제일 부드러운 길이야: 당연한 재귀를 쓰고, 캐시를 더해. 종종 지수 재앙을 선형 시간 해법으로 바꾸는 한 줄 변경이야."
재귀 더하기 캐시
메모이제이션은 top-down DP 야: 문제를 직접 거울처럼 비추는 자연스러운 재귀 해법을 쓰고, 각 부분 문제 답을 처음 계산할 때 기억하는 캐시를 더해. 같은 부분 문제에 대한 나중 모든 요청이 다시 계산된 서브트리 대신 즉시 조회. top-down 이라 불리는 건 큰 문제에서 시작해 base case 쪽으로 아래로 재귀하며, 재귀가 풀릴 때 결과를 캐시하니까. 아름다움: 아무것도 재설계 안 해도 돼 — 맞지만 느린 재귀를 가져다 기억으로 빠르게 만들어.
캐시 키가 상태다
못 박을 개념 하나: 캐시는 부분 문제의 상태로 키 매겨져 — 편리하게도, 정확히 함수의 인자야. fib(7) 의 상태는 7; edit_distance(i, j) 의 상태는 쌍 (i, j). 같은 인자의 두 호출은 같은 부분 문제고 같은 답을 반환해야 해, 그래서 인자가 완벽한 캐시 키. Python 에선 거의 공짜야: 함수를 @functools.cache (또는 @lru_cache) 로 데코레이트하면 인자로 키 매겨져 캐싱이 자동으로 일어나. 맞는 재귀가 말 그대로 한 줄로 top-down DP 가 돼.
거래
메모이제이션의 강점: 가장 쉬운 DP 라 쓰기 (이미 믿는 재귀를 캐시할 뿐), 그리고 지연 (lazy) — 네 쿼리에 답하는 데 실제 필요한 부분 문제만 계산해, bottom-up 테이블이 채우느라 시간 낭비할 닿을 수 없는 상태를 건너뛰어. 약점: 콜 스택을 타, 그래서 아주 깊은 상태 사슬이 재귀 한계를 칠 수 있고 (재귀-트랙 주의), 캐시가 메모리랑 조회 오버헤드를 좀 져. 대부분 문제엔, 메모이제이션이 맞는 첫 수 — bottom-up 테이블 (다음 lesson) 은 깊이나 공간이 강제할 때만 손대.
피파의 고백
@cache 를 쳤고 타임아웃에서 즉시로 갔어. 살짝 속은 기분이었어 — 그게 동적 계획법이야? 근데 그게 top-down DP 의 정직한 진실이야: 재귀가 맞으면, 메모이제이션이 종종 데코레이터 하나 거리야. 어려운 부분은 캐싱이 아니라 맞는 점화식 쓰기였고, 그건 이미 했어.