Start by setting base cases in the table, then fill each cell by checking if including the current item improves the value, moving from smaller subproblems to bigger ones.
Execution Sample
DSA Typescript
const weights = [1, 3, 4];
const values = [1, 4, 5];
const W = 7;
const dp = Array(weights.length + 1).fill(0).map(() => Array(W + 1).fill(0));
for (let i = 1; i <= weights.length; i++) {
for (let w = 1; w <= W; w++) {
if (weights[i-1] <= w) {
dp[i][w] = Math.max(dp[i-1][w], dp[i-1][w - weights[i-1]] + values[i-1]);
} else {
dp[i][w] = dp[i-1][w];
}
}
}
This code fills a DP table to solve the 0/1 Knapsack problem using bottom-up tabulation.
Execution Table
Step
Operation
Item Index (i)
Capacity (w)
Condition (weights[i-1] <= w)
DP[i][w] Computed
DP Table Row i State
1
Initialize base row
0
0 to 7
N/A
0
[0,0,0,0,0,0,0,0]
2
i=1, w=1
1
1
1 <= 1: true
max(dp[0][1], dp[0][0] + 1) = max(0,0+1)=1
[0,1,0,0,0,0,0,0]
3
i=1, w=2
1
2
1 <= 2: true
max(dp[0][2], dp[0][1] + 1) = max(0,0+1)=1
[0,1,1,0,0,0,0,0]
4
i=1, w=3
1
3
1 <= 3: true
max(dp[0][3], dp[0][2] + 1) = max(0,0+1)=1
[0,1,1,1,0,0,0,0]
5
i=1, w=4
1
4
1 <= 4: true
max(dp[0][4], dp[0][3] + 1) = max(0,0+1)=1
[0,1,1,1,1,0,0,0]
6
i=1, w=5
1
5
1 <= 5: true
max(dp[0][5], dp[0][4] + 1) = max(0,0+1)=1
[0,1,1,1,1,1,0,0]
7
i=1, w=6
1
6
1 <= 6: true
max(dp[0][6], dp[0][5] + 1) = max(0,0+1)=1
[0,1,1,1,1,1,1,0]
8
i=1, w=7
1
7
1 <= 7: true
max(dp[0][7], dp[0][6] + 1) = max(0,0+1)=1
[0,1,1,1,1,1,1,1]
9
i=2, w=1
2
1
3 <= 1: false
dp[1][1] = 1
[0,1,1,1,1,1,1,1]
10
i=2, w=2
2
2
3 <= 2: false
dp[1][2] = 1
[0,1,1,1,1,1,1,1]
11
i=2, w=3
2
3
3 <= 3: true
max(dp[1][3], dp[1][0] + 4) = max(1,0+4)=4
[0,1,1,4,1,1,1,1]
12
i=2, w=4
2
4
3 <= 4: true
max(dp[1][4], dp[1][1] + 4) = max(1,1+4)=5
[0,1,1,4,5,1,1,1]
13
i=2, w=5
2
5
3 <= 5: true
max(dp[1][5], dp[1][2] + 4) = max(1,1+4)=5
[0,1,1,4,5,5,1,1]
14
i=2, w=6
2
6
3 <= 6: true
max(dp[1][6], dp[1][3] + 4) = max(1,4+4)=8
[0,1,1,4,5,5,8,1]
15
i=2, w=7
2
7
3 <= 7: true
max(dp[1][7], dp[1][4] + 4) = max(1,5+4)=9
[0,1,1,4,5,5,8,9]
16
i=3, w=1
3
1
4 <= 1: false
dp[2][1] = 1
[0,1,1,4,5,5,8,9]
17
i=3, w=2
3
2
4 <= 2: false
dp[2][2] = 1
[0,1,1,4,5,5,8,9]
18
i=3, w=3
3
3
4 <= 3: false
dp[2][3] = 4
[0,1,1,4,5,5,8,9]
19
i=3, w=4
3
4
4 <= 4: true
max(dp[2][4], dp[2][0] + 5) = max(5,0+5)=5
[0,1,1,4,5,5,8,9]
20
i=3, w=5
3
5
4 <= 5: true
max(dp[2][5], dp[2][1] + 5) = max(5,1+5)=6
[0,1,1,4,5,6,8,9]
21
i=3, w=6
3
6
4 <= 6: true
max(dp[2][6], dp[2][2] + 5) = max(8,1+5)=8
[0,1,1,4,5,6,8,9]
22
i=3, w=7
3
7
4 <= 7: true
max(dp[2][7], dp[2][3] + 5) = max(9,4+5)=9
[0,1,1,4,5,6,8,9]
💡 All items and capacities processed; final answer dp[3][7] = 9
Variable Tracker
Variable
Start
After Step 8
After Step 15
After Step 22 (Final)
i (item index)
0
1
2
3
w (capacity)
0
7
7
7
dp[1]
[0,0,0,0,0,0,0,0]
[0,1,1,1,1,1,1,1]
[0,1,1,1,1,1,1,1]
[0,1,1,1,1,1,1,1]
dp[2]
[0,0,0,0,0,0,0,0]
[0,1,1,1,1,1,1,1]
[0,1,1,4,5,5,8,9]
[0,1,1,4,5,5,8,9]
dp[3]
[0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0]
[0,1,1,4,5,6,8,9]
Key Moments - 3 Insights
Why do we start filling the DP table from i=1 and w=1, not from 0?
Row 0 and column 0 represent base cases with no items or zero capacity, so their values are zero. Filling starts from i=1 and w=1 to build on these base cases, as shown in execution_table rows 2 and 3.
Why do we use dp[i-1][w - weights[i-1]] + values[i-1] when weights[i-1] <= w?
This expression means including the current item: we add its value to the best solution for the remaining capacity (w - weights[i-1]) without this item (i-1). This is the core of the bottom-up approach, seen in execution_table rows like 11 and 20.
Why do we take the max between including and excluding the current item?
We want the best value possible. Including the item might increase value, but if it doesn't fit or is worse, excluding it is better. The max function ensures we pick the best option, as shown in many steps like 11 and 20.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 11. What is the value of dp[2][3]?
A1
B4
C0
D5
💡 Hint
Check the 'DP[i][w] Computed' column at step 11 in the execution_table.
At which step does the DP table first show a value greater than 5 in row 3?
AStep 20
BStep 18
CStep 19
DStep 22
💡 Hint
Look at the 'DP Table Row i State' column for row 3 in the execution_table from step 18 to 22.
If the weight of the second item changed from 3 to 2, how would dp[2][2] change at step 10?
AIt would become 5
BIt would remain 1
CIt would become 4
DIt would become 0
💡 Hint
If weights[1] <= w at w=2, dp[2][2] would be max of excluding or including item 2, see step 11 logic.
Concept Snapshot
Tabulation Bottom Up DP:
- Create a 2D DP table with items as rows and capacities as columns.
- Initialize first row and column with zeros (base cases).
- Fill table row by row, capacity by capacity.
- For each cell, choose max of excluding or including current item.
- Final answer at dp[number_of_items][max_capacity].
Full Transcript
Tabulation Bottom Up Dynamic Programming solves problems by building a table from smaller to bigger subproblems. We start with base cases where no items or zero capacity means zero value. Then, for each item and capacity, we decide whether to include the item or not by comparing values. This fills the table step by step until the final answer is found at the bottom-right cell. The example code and table show this process clearly, with each step updating the DP table based on previous results.