Notes & software courses · Free to learn
Aph's Blog
On this page

บทเรียน: Dynamic Programming

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

หัวข้อที่คนกลัวที่สุด แต่จับหลักได้ไม่ยาก — แบ่งปัญหาย่อยที่ซ้ำกันแล้วเก็บผลไว้ใช้ซ้ำ

Dynamic Programming (DP) ใช้เมื่อปัญหาแตกเป็นปัญหาย่อยที่ซ้ำกัน (overlapping subproblems) วิธีคือเก็บผลลัพธ์ย่อยไว้ใช้ซ้ำ (memoization) ไม่ต้องคำนวณใหม่ เคล็ดลับคือเริ่มจากเขียน recursion ปกติก่อน แล้วค่อยเพิ่ม cache

Fibonacci — เห็นความซ้ำชัดที่สุด

python
# แบบช้า: คำนวณซ้ำมหาศาล O(2^n)
def fib_slow(n):
    if n <= 1:
        return n
    return fib_slow(n - 1) + fib_slow(n - 2)

# แบบ DP: จำผลลัพธ์ไว้ O(n)
def fib(n, memo={}):
    if n <= 1:
        return n
    if n in memo:
        return memo[n]
    memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
    return memo[n]

print(fib(30))  # 832040 (เร็วมาก)

2 แนวทางของ DP

  • Top-down (memoization) — เขียน recursion แล้วเก็บผลลัพธ์ใน dict/array
  • Bottom-up (tabulation) — สร้างตารางแล้วไล่เติมจากเล็กไปใหญ่
วิธีฝึก DP

อย่าพยายามคิด DP ออกทีเดียว ให้เขียน brute force recursion ให้ถูกก่อน แล้วถามตัวเองว่า "มีการคำนวณซ้ำตรงไหน" จากนั้นเพิ่ม cache โจทย์คลาสสิก: coin change, longest common subsequence, knapsack, climbing stairs