DP trên chuỗi và lưới (Grid & String DP)
DP trên lưới là một họ bài toán cực kỳ trực quan: bạn đứng ở một ô và chỉ được đi theo vài hướng cho phép (thường sang phải và xuống dưới). Mỗi ô lưu lời giải tối ưu để tới được ô đó. Bạn sẽ học ba bài: đếm số đường đi, tổng đường đi nhỏ nhất (min path sum), và một bài DP trên chuỗi rất đẹp — chuỗi con đối xứng (palindrome) dài nhất.
1. Trực quan: ô này tới từ đâu?
Trên lưới, câu hỏi cốt lõi cho mỗi ô là: "tôi có thể bước vào ô này từ những ô nào?" Nếu chỉ được
đi phải và xuống, thì ô (i, j) chỉ có thể tới từ ô trên (i-1, j) hoặc ô trái
(i, j-1). Mọi truy hồi trên lưới đều mọc ra từ quan sát đơn giản này.
(i-1, j)
|
v
(i,j-1) -> (i, j) o (i,j) den tu TREN hoac TRAI
2. Bài 1 — Đếm số đường đi
Lưới m × n, robot ở góc trên-trái, chỉ đi phải hoặc xuống, đếm số đường tới góc dưới-phải.
dp[i][j] = số đường tới ô (i, j). Vì tới (i, j) chỉ từ trên hoặc trái:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
Hang dau va cot dau toan 1 (chi 1 cach di thang):
1 1 1 1
1 2 3 4
1 3 6 10
1 4 10 20 <- 20 duong toi goc duoi-phai (luoi 4x4)
3. Bài 2 — Tổng đường đi nhỏ nhất (min path sum)
Mỗi ô lưới mang một chi phí. Đi từ góc trên-trái xuống góc dưới-phải (chỉ phải/xuống), tìm tổng chi phí nhỏ nhất.
dp[i][j] = tổng nhỏ nhất để tới (i, j). Tới (i, j) từ ô rẻ hơn trong hai ô trên/trái, rồi cộng
chi phí ô hiện tại:
dp[i][j] = grid[i][j] + min( dp[i-1][j], dp[i][j-1] )
grid: dp (tong nho nhat):
1 3 1 1 4 5
1 5 1 -> 2 7 6
4 2 1 6 8 7 <- dap an 7 (duong 1->3->1->1->1)
4. Bài 3 — Chuỗi con đối xứng dài nhất (longest palindromic substring)
Một palindrome là chuỗi đọc xuôi ngược như nhau ("aba", "abba"). Tìm chuỗi con liền kề
đối xứng dài nhất trong một chuỗi cho trước.
Đặt dp[i][j] = True nếu đoạn từ i tới j là palindrome. Quan sát: đoạn i..j đối xứng khi
hai đầu khớp s[i] == s[j] và phần lõi bên trong i+1 .. j-1 cũng đối xứng:
dp[i][j] = (s[i] == s[j]) AND dp[i+1][j-1]
"babad": cac doan do la palindrome:
"b","a","b","a","d" (do dai 1)
"bab" (i=0,j=2): s[0]=s[2]='b' va loi "a" doi xung -> True
"aba" (i=1,j=3): tuong tu -> True
=> dai nhat: "bab" hoac "aba", do dai 3
Vì dp[i][j] cần dp[i+1][j-1] (đoạn ngắn hơn), ta duyệt theo độ dài tăng dần.
5. Phân tích chung
| Bài | dp[i][j] nghĩa là | Truy hồi | Thời gian |
|---|---|---|---|
| Đếm đường | số đường tới (i,j) | dp[i-1][j] + dp[i][j-1] | O(m·n) |
| Min path sum | tổng nhỏ nhất tới (i,j) | grid[i][j] + min(trên, trái) | O(m·n) |
| Palindrome | đoạn i..j có đối xứng không | s[i]==s[j] and dp[i+1][j-1] | O(n^2) |
Bẫy thường gặp:
- Quên khởi tạo hàng đầu / cột đầu trên lưới (chúng chỉ có một hướng đi tới).
- Với palindrome, thứ tự duyệt phải theo độ dài tăng dần, nếu không
dp[i+1][j-1]chưa được tính. - Trường hợp đặc biệt độ dài 2 (
"bb"): không có "lõi" bên trong nên xử lý riêng.
6. Mẫu nhận diện
- Đề có lưới/bàn cờ và đi theo hướng cố định → DP lưới với
dp[i-1][j],dp[i][j-1]. - "Đếm số đường", "đường rẻ nhất/đắt nhất" trên bảng → DP lưới.
- Câu hỏi về đoạn con đối xứng / con liền kề trên chuỗi → DP trên đoạn
[i, j].
7. 🎮 Trò chơi: DP chuỗi/lưới
8. Quiz kiểm tra nhanh
9. Hoàn thành
…☑️ Tiếp theo: 3.4.5 — Tối ưu không gian DP (cuộn mảng: giảm bộ nhớ từ O(n·m) xuống O(m)).