Worked examples — Tabulation (bottom-up DP) — iterative
3.7.8 · D3· Coding › Algorithm Paradigms › Tabulation (bottom-up DP) — iterative
Yeh parent Tabulation note ka "sleeves chadhao aur karo" companion hai. Wahan humne 5-step recipe seekhi thi (State, Recurrence, Base, Order, Answer). Yahan hum use har tarah ke case ke khilaf stress-test karenge jo ek tabulation problem de sakti hai — including woh ugly wale jo parent note ne sirf hint kiye the.
Shuru karne se pehle, ek promise: har symbol kamaya hua hai. dp[i] ka matlab sirf "woh answer jo humne boxes ki ek list mein box number mein store kiya." Ek table woh boxes ki list hai. Shelf par rakhe labelled shoeboxes ki ek row se zyada mysterious kuch nahi.
Scenario matrix
Ek tabulation problem ko ek machine ki tarah socho. Kaise inputs use jam kar sakte hain? Yeh hai "case classes" ka poora menu — neeche har worked example tagged hai un cell(s) ke saath jo woh cover karta hai.
| Cell | Case class | Tricky kyon hai | Covered by |
|---|---|---|---|
| C1 | 1D table, additive recurrence | easy baseline | Ex 1 |
| C2 | Degenerate / tiny input (, empty set) | base case hi poora answer hai | Ex 2 |
| C3 | 2D table, binary "take/skip" choice | previous row se do dependencies | Ex 3 |
| C4 | Impossible / "no solution" state | ya safely represent karna zaroori | Ex 4 (Coin Change) |
| C5 | Order matters — galat loop direction sab bigaad deta hai | high→low vs low→high | Ex 5 |
| C6 | Do strings, 2D grid, match-vs-mismatch | diagonal dependency | Ex 6 (LCS) |
| C7 | Real-world word problem | English → state translate karna | Ex 7 |
| C8 | Exam twist: ek "trap" recurrence | obvious recurrence galat hai | Ex 8 |
Hum aath examples mein aath cells cover karenge. Chalo shuru karte hain.
Ex 1 — C1: additive baseline (Tribonacci)
Forecast: aage padhne se pehle guess karo ki 10 ke kareeb hai ya 25 ke.
- State.
dp[i]= -waan Tribonacci number. Yeh step kyon? Hum pehle box ka naam rakhte hain taaki recurrence ke paas kuch concrete ho fill karne ke liye. - Recurrence.
dp[i] = dp[i-1] + dp[i-2] + dp[i-3]. Yeh step kyon? Definition literally teen predecessors ko sum karti hai — yahi optimal substructure hai. - Base cases.
dp[0]=0, dp[1]=1, dp[2]=1. Yeh step kyon? par recurrencedp[-1]padhti, jo exist nahi karta. Deepest reach-back cover karne ke liye hume enough boxes seed karne honge (yahan, 3 boxes). - Order. Increasing . Yeh step kyon? Jab hum
dp[i]fill karte hain,dp[i-1], dp[i-2], dp[i-3]sab already likhe hue hain. - Answer.
dp[6].
Shelf ko left se right fill karna — main har naya box words mein likhta hoon taaki kuch loop ke andar chhupa na rahe:
dp[3].dp[4].dp[5].dp[6].
| i | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| dp[i] | 0 | 1 | 1 | 2 | 4 | 7 | 13 |
Verify: 3 consecutive earlier boxes ki kisi bhi window ka sum agla deta hai — e.g. . ✅ Answer 13 (10 ke kareeb — kya tumhara forecast sahi nikla?).
Ex 2 — C2: degenerate input
Forecast: zero stairs — kya answer 0 ways hai, ya 1 way?
- State.
dp[i]= step tak pahunchne ke distinct ways ki sankhya. Yeh step kyon? Hume decide karna hoga ki "step 0 tak pahunchne" ka matlab kya hai answer dene se pehle. - Base case reasoning. "Zero stairs chadhne" ka exactly ek tarika hai: kuch mat karo. Moves ka woh empty sequence ek valid way hai. Yeh step kyon? Yahan sabse common bug
dp[0]=0likhna hai. Lekin 0 matlab hoga "impossible," jo galat hai — khari rehna ek way hai. - Koi recurrence nahi chalti. ke liye woh loop jo
dp[2], dp[3], …fill karta, woh kabhi start hi nahi hota (index 2 aur index 0 ke beech kuch nahi hai). Toh answer seedha base cell se padha jaata hai — yeh exactly woh case hai jahan base case hi poora answer hai. - Answer.
dp[0] = 1.
Verify: ; aur downstream (do real ways: 1,1 aur 2). ✅ Answer 1 way.
Ex 3 — C3: 2D take/skip (0-1 Knapsack full trace)
Forecast: kya hum value 5 se better kar sakte hain?
Pehle, notation — har symbol use se pehle define:
Hum ek grid banate hain: rows = "pehle items available", columns = "capacity 0 se 4 tak." dp[i][c] = pehle items use karke capacity ke saath best value.
Recurrence (parent note se), ab ki sab define ho gaye hain:
Previous row se do dependencies kyon? Kyunki item ya toh bahar hai (same par upar wali row copy karo) ya andar hai (uski value plus earlier items ki best packing leftover capacity mein — woh bhi upar wali row se).
Neeche di gayi figure exactly yeh do arrows dikhati hai. Ise aise padho: yellow cell (neeche, pink ?) woh dp[i][c] hai jo hum compute kar rahe hain. Upar se seedha neeche wala blue arrow "skip" choice hai — woh dp[i-1][c] copy karta hai. Pink diagonal arrow dp[i-1][c-w_i] se aata hai jo aur left hai (leftover capacity pay karne ke baad) aur "take" choice represent karta hai, jisme hum add karte hain. Jo bada hoga woh rakh lete hain.

Row 0 (koi item nahi) = sab zeros — zero items available hone par tum kabhi value nahi kama sakte, capacity chahe kuch bhi ho. Ab har cell words mein fill karo:
- Row 1, item . Har ke liye: skip = 0, take = . Toh
dp[1][1..4]sab 1 ho jaate hain;dp[1][0]=0(weight 1 bhi fit nahi hoti). - Row 2, item .
dp[2][0]=dp[2][1]=dp[2][2]=row 1 copy (weight 3 fit nahi hoti) .dp[2][3]: skip , take ; max .dp[2][4]: skip , take ; max . - Row 3, item . wale cells row 2 copy karte hain.
dp[3][4]: skip , take ; max (ek tie — item 3 akela items 1+2 ke barabar hai).
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
| 0 (none) | 0 | 0 | 0 | 0 | 0 |
| 1 (1,1) | 0 | 1 | 1 | 1 | 1 |
| 2 (3,4) | 0 | 1 | 1 | 4 | 5 |
| 3 (4,5) | 0 | 1 | 1 | 4 | 5 |
- Order. Rows increasing. Yeh step kyon? Har read row se hoti hai, jo already finish hai.
- Answer. Bottom-right cell
dp[3][4] = 5.
Verify: fit karne wale sab subsets enumerate karo: {} →0, {1}→1, {2}→4, {3}→5, {1,2}: w=4,v=5 ✓, {1,3}: w=5 ✗, {2,3}: w=7 ✗, {1,2,3}: w=8 ✗. Best feasible value = 5. ✅
Ex 4 — C4: "impossible" state (Coin Change — minimum coins)
Forecast: greedy ek 4 pakad leta, phir 2 chahiye → 4+1+1 = teen coins. Kya hum isse better kar sakte hain?
Yahan table mein ek impossible entry ho sakti hai — kuch amounts unmakeable ho sakte hain. Hume ek aisi value chahiye jo "no solution" ka matlab de aur min mein survive kare.
- State.
dp[a]= amount sum karne ke liye fewest coins. Yeh step kyon? 0 se target tak har amount ke liye ek box. - Sentinel initialisation. Har
dp[a]koINF(jaise upar define kiya) se initialise karo, exceptdp[0]=0. Yeh step kyon?INFmatlab "abhi tak reachable nahi." Kyunki humminlete hain, ek unreachable path kabhi nahi jeetega. - Recurrence. Har amount aur coin ke liye:
Yeh step kyon? Ek coin use karne se ek chhota subproblem bachta hai; 1 add karo us coin ke liye jo humne abhi spend kiya. Agar abhi bhi
INFhai, toh effectivelyINFrehta hai aurminhaar jaata hai — impossibility safely propagate hoti hai. - Order. 1 se target tak. Yeh step kyon? ki amount chhoti hai, already finalized.
- Answer.
dp[target], ya "impossible" ( mein convert karo) agar woh abhi bhiINFhai.
Words mein fill karna (coins ):
dp[1]: sirf coin 1 fit hoti hai → .dp[2]: sirf coin 1 fit hoti hai → .dp[3]: coin 1 → ; coin 3 → ; min .dp[4]: coin 1 → ; coin 3 → ; coin 4 → ; min .dp[5]: coin 1 → ; coin 3 → ; coin 4 → ; min .dp[6]: coin 1 → ; coin 3 → ; coin 4 → ; min .
| a | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| dp[a] | 0 | 1 | 2 | 1 | 1 | 2 | 2 |
Toh dp[6] = 2 (coins ). Greedy ke 3 se better!
Impossible case: sirf coins ke saath, dp[1] aur dp[2] kabhi reach nahi hote (koi coin nahi hai), toh woh INF pe rahte hain — amount 1 ya 2 genuinely unmakeable hai, aur humara sentinel woh cleanly report karta hai bina kisi baad ke min ko corrupt kiye.
Verify: 2 coins use karta hai; koi single coin 6 ke barabar nahi aur koi coin pair 2 se better nahi, toh minimum = 2. Aur ke saath, amount = impossible. ✅
Ex 5 — C5: order matters (1D space-optimised knapsack)
Forecast: agar hum capacity loop low→high chalayein, kya answer bahut bada hoga ya bahut chhota?
Hum sirf ek row rakhte hain aur use in-place update karte hain. Recurrence ban jaata hai dp[c] = max(dp[c], v_i + dp[c-w_i]), wohi use karke (item ka weight/value) jo Ex 3 mein define kiye. Subtlety: dp[c-w_i] abhi bhi previous item ki value represent karna chahiye, is item ki freshly-updated value nahi (woh same item do baar pick karne deta — 0/1 break hota). (Dekho Space Optimization in DP.)
Figure danger clearly dikhati hai. Cells ki single row hamare dp[c] shelf hai, . Upar yellow arrow safe sweep direction dikhata hai (high→low). Jab hum yellow upd cell dp[4] update karte hain, pink curved arrow dikhata hai ki woh apne left wale blue old cell ko read kar raha hai — aur kyunki hum right se sweep karte hain, woh left cell is round mein abhi overwrite nahi hua, toh woh abhi bhi previous item ki value rakhta hai. Doosri taraf sweep karo aur woh left cell already is-round ki value hogi → item reuse ho jaayegi.

- Correct — loop high→low. Jab hum
dp[4]likhte hain, uske left wala celldp[4-w]abhi bhi last-round ki value hai kyunki is round mein humne usse abhi touch nahi kiya. Yeh step kyon? High→low guarantee karta hai ki read ek not-yet-overwritten (i.e. previous-row) cell se ho. - Wrong — loop low→high. Hum pehle
dp[1]update karenge, phirdp[2]abhi-abhi-updateddp[1]padh sakta hai, effectively ek item reuse karte hue.
Concrete failure item ke saath zeros se start karke, low→high (main har update order mein likhta hoon): dp[1]=max(0,1+dp[0])=1, phir dp[2]=max(0,1+dp[1])=2, phir dp[3]=max(0,1+dp[2])=3, phir dp[4]=max(0,1+dp[3])=4 — item 1 chaar baar use kiya! Yeh unbounded knapsack hai, 0/1 nahi.
Poori item list par high→low sahi 5 deta hai (Ex 3 ke dp[3][4] se match karta hai).
Verify: correct 1D high→low answer = 5 (2D result ke barabar). Buggy low→high ek single item par ke saath 4 deta hai (galat, item reused). ✅
Ex 6 — C6: do strings, diagonal dependency (LCS)
Forecast: LCS length guess karo — 3, 4, ya 5?
Ek subsequence order rakhta hai lekin letters skip kar sakta hai. Pehle, do strings ka naam rakho taaki recurrence unambiguous ho:
Recurrence mein ek match case aur ek mismatch case hai:
Figure teen neighbours dikhati hai jis par har cell depend karta hai. Pink ? cell woh dp[i][j] hai. Ek match par (yellow diagonal arrow) woh up-left cell dp[i-1][j-1] copy karke 1 add karta hai — shared last letter ek common subsequence cap karta hai, baaki strictly-smaller prefixes mein rehta hai. Ek mismatch par (do pink arrows) woh up cell dp[i-1][j] ( ka last letter drop karo) aur left cell dp[i][j-1] ( ka last letter drop karo) mein se bada leta hai.

Ab poori 5-step recipe apply karo:
- State.
dp[i][j]= ke pehle letters aur ke pehle letters ke LCS ki length (jaise upar define kiya). - Recurrence. Upar dikhaye gaye match/mismatch cases. Yeh step kyon? Agar last letters match karte hain toh unhe ek common subsequence ki tail ke roop mein reuse kiya ja sakta hai; agar nahi toh answer do mein se ek last letter ignore karta hai, toh hum dono try karte hain aur better rakhte hain.
- Table dimensions & base. size ki grid
dpallocate karo — empty prefix ke liye ek extra row aur column. Row 0 aur column 0 sab zeros se initialise karo. Yeh step kyon? Ek empty string kisi bhi cheez ke saath koi letter share nahi karti, toh uski LCS length 0 hai; aur ya par recurrence ko valid row 0 / column 0 padhnee padti hai. - Order. Row by row fill karo (increasing ), aur har row ke andar left se right (increasing ). Yeh step kyon? Har cell up (
dp[i-1][j]), left (dp[i][j-1]) aur up-left (dp[i-1][j-1]) padhta hai; yeh order guarantee karta hai ki teeno unhe padhne se pehle already fill ho chuke hain. - Answer. Bottom-right cell
dp[|X|][|Y|] = dp[7][5]. Yeh step kyon? Woh cell poore ka poore ke against LCS hai.
Yeh hai poori table (rows = ABCBDAB ke letters top-to-bottom, columns = BDCAB ke letters left-to-right). Row/col 0 empty-prefix zeros hain.
| ∅ | B | D | C | A | B | |
|---|---|---|---|---|---|---|
| ∅ | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 0 | 0 | 0 | 1 | 1 |
| B | 0 | 1 | 1 | 1 | 1 | 2 |
| C | 0 | 1 | 1 | 2 | 2 | 2 |
| B | 0 | 1 | 1 | 2 | 2 | 3 |
| D | 0 | 1 | 2 | 2 | 2 | 3 |
| A | 0 | 1 | 2 | 2 | 3 | 3 |
| B | 0 | 1 | 2 | 2 | 3 | 4 |
Kuch cells padho rules fire hote dekhne ke liye:
- Row
A, colA: letters match karte hain (A=A) → up-left0+ 1 = 1. - Row
B, colB(last column): match (B=B) → up-left cell (rowA, colA= 1) + 1 = 2. - Row
C, colC: match → up-left (rowB, colD= 1) + 1 = 2. - Bottom-right (row
B, colB): match → up-left (rowA, colA= 3) + 1 = 4. - Ek mismatch example — row
B, colD:B≠D→ max(up = 0, left = 1) = 1.
Bottom-right cell 4 hai — ek witnessing subsequence "BCAB" hai.
Verify: "BCAB" dono ABCBDAB aur BDCAB mein order mein appear hota hai, aur koi length-5 common subsequence exist nahi karta. LCS length = 4. ✅
Ex 7 — C7: real-world word problem (max non-adjacent loot)
Forecast: do sabse bade, 9 aur 7 pakadna clash hoga (adjacent hain). Real max kya hai?
English constraint "koi do adjacent nahi" har ghar ke liye ek take/skip decision ban jaata hai — pure tabulation. matlab "ghar mein cash" (0-indexed: ).
- State.
dp[i]= houses consider karte hue max loot. Yeh step kyon? Informal goal ko ek box meaning mein translate karo. - Recurrence. House jiske paas cash hai, ya toh use skip karo (
dp[i-1]rakho) ya rob karo ( lo plus do houses peeche se best,dp[i-2], kyunki ab forbidden hai): kyon? House robbing karna house ban karta hai; nearest safe prior state hai. - Base.
dp[0]=a_0=2;dp[1]=max(a_0,a_1)=max(2,7)=7. Yeh step kyon? Ek ya do houses ke saath "two back" recurse karne ke liye kuch nahi hai. - Order. Increasing ; Answer.
dp[4].
Words mein fill karna:
dp[2].dp[3].dp[4].
| i | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 2 | 7 | 9 | 3 | 1 | |
| dp[i] | 2 | 7 | 11 | 11 | 12 |
Verify: houses loot karo. Adjacency avoid karne wala koi bhi set: , , — koi 12 nahi beat karta. Max = 12. ✅
Ex 8 — C8: exam trap (ek galat "obvious" recurrence)
Forecast: {1,2} se 4 ki combinations hain: 1+1+1+1, 1+1+2, 2+2 → 3 ways. Kya student ka formula 3 dega?
-
Trap, work out karke. Student ka
dp[a]=dp[a-1]+dp[a-2]Fibonacci/stairs shape hai — lekin woh ordered sequences count karta hai (woh poochha "kya last piece ek 1 tha ya 2?", jo order distinguish karta hai). Actuallydp[0]=1, dp[1]=1ke saath chalate hain:dp[2].dp[3].dp[4].
Toh student ko 5 milta hai. Woh 5 hain ordered writings
1111, 112, 121, 211, 22— woh112,121,211ko teen alag cheezein count karta hai, ek combination "do 1's aur ek 2" ko overcount karta hai. Yeh step kyon? Hume galat number appear hote dekhna hoga taaki fix par trust aaye. -
Fix — coin outer loop. Combinations count karne ke liye, coins ko bahar iterate karo, amounts andar:
dp = [0]*(amount+1); dp[0] = 1 for c in coins: # ek coin type ke baare mein ek baar mein decide karo for a in range(c, amount+1): dp[a] += dp[a-c]Yeh step kyon (zaroori justification)? Coin loop ko bahar rakhne ka matlab hai hum coin 1 ke baare mein saare decisions coin 2 ko kabhi touch karne se pehle finish karte hain. Jab hum coin 2 par move karte hain, hum sirf 1's se already bane amounts ke upar 2's append kar sakte hain — hum kabhi wapas nahi jaate aur 2 ke baad ek 1 interleave nahi karte. Woh fixed processing order (sab 1's, phir sab 2's) har multiset ko exactly ek canonical order mein appear karaata hai, toh
112vs121jaise reorderings kabhi dono count nahi ho sakte. Loops swap karo (amount bahar, coin andar) aur tum phir se har ordering introduce karte — waapis permutations count karne lage. -
Trace (coins , amount 4). Coin-1 pass ke baad, har amount ka exactly ek way hai (sab 1's):
dp = [1,1,1,1,1]. Ab coin-2 passdp[a] += dp[a-2]karta hai ke liye:dp[2] += dp[0]: .dp[3] += dp[1]: .dp[4] += dp[2]: .
| a | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| after coin 1 | 1 | 1 | 1 | 1 | 1 |
| after coin 2 | 1 | 1 | 2 | 2 | 3 |
- Answer.
dp[4] = 3— hamare hand count{1111, 112, 22}se match karta hai.
Verify: {1,2} se 4 ki combinations = {1111,112,22} = 3; naive stairs recurrence 5 tak overcount karta hai. ✅
Recall Koi bhi tabulation code karne se pehle scenario checklist
- Kya maine degenerate input (empty / zero) handle kiya? (Ex 2)
- Kya koi state "impossible" matlab rakhti hai — aur kya mera sentinel
min/max-safe hai? (Ex 4) - Kya meri loop direction in-place / 1D collapse ke liye sahi hai? (Ex 5)
- Kya main order count kar raha hoon ya combinations — kya loop nesting sahi hai? (Ex 8)
Active recall
Tribonacci base cases — tumhe kitne chahiye aur kyon?
Climbing-stairs / counting DP mein dp[0]=1 (0 nahi) kyon?
Coin Change min-coins mein, unreachable cells ko ∞ se initialise kyon karein, −1 se nahi?
1D 0/1 knapsack: kaunsi capacity loop direction aur kyon?
LCS match vs mismatch recurrence?
LCS table dimensions aur base?
House robber recurrence?
Coin Change: ordered count vs combination count — kya badalta hai?
Connections
- Tabulation (bottom-up DP) — iterative (index 3.7.8) — woh parent recipe jise yeh examples exercise karte hain
- 0-1 Knapsack, Coin Change, Longest Common Subsequence — yahan trace ki gayi classic tables
- Space Optimization in DP — Ex 5 ka 1D collapse
- Recurrence Relations — har recurrence kahan se aati hai
- Optimal Substructure, Overlapping Subproblems — kyon har example kaam karta hai
- Memoization (top-down DP) — top-down twin