dp[i][j] depends on dp[i-1][j], dp[i][j-1] (or similar neighbors)
When to useUnique paths, min path sum, maximal square, cherry pickup
dp
Maximal Minimum Value Path I
maximum_minimum_value_path_iPlumber
plumberGrid DP Introduction
dp_grid_introMaximal Square
maximal_squareMinimum Difficulty of a Job Schedule
min_job_difficultyMinimum Path Sum
minimal_path_sumMinimum Total Container Size
minimum_total_container_sizeNumber of Unique Paths to Go from Top Left to Bottom Right
robot_unique_pathLongest Palindromic Substringmedium
longest_palindromic_substring · no slotsPalindromic Substringsmedium
palindromic_substrings · no slotsUnique Pathsmedium
unique_paths · no slotsUnique Paths II
unique_paths_with_obstaclesDungeon Game
dungeon_gameDECLARE
dp = m × n table initialized
const dp = Array.from({ length: m }, () => new Array(n).fill(0));dp[0][0] = grid[0][0];
—
const m = grid.length, n = grid[0].length;const dp = Array.from({ length: m }, () => new Array(n).fill(0));
const dp = Array.from({ length: m }, () => new Array(n).fill(0));let best = 0;
const dp = Array.from({ length: d + 1 }, () => new Array(n + 1).fill(Infinity));dp[0][0] = 0;
const dp = Array.from({ length: m }, () => new Array(n).fill(0));dp[0][0] = grid[0][0];
const dp = Array.from({ length: days + 1 }, () => new Array(n + 1).fill(Infinity));dp[0][0] = 0;
const dp = Array.from({ length: m }, () => new Array(n).fill(1));
—
—
—
const dp = Array.from({ length: m }, () => new Array(n).fill(0));if (obstacleGrid[0][0] === 1) return 0;dp[0][0] = 1;
const dp = Array.from({ length: m }, () => new Array(n).fill(0));dp[m - 1][n - 1] = Math.max(1, 1 - dungeon[m - 1][n - 1]);
BASE CASES
initialize first row and first column
for (let i = 1; i < m; i++) dp[i][0] = Math.min(dp[i-1][0], grid[i][0]);for (let j = 1; j < n; j++) dp[0][j] = Math.min(dp[0][j-1], grid[0][j]);
—
dp[0][0] = grid[0][0];for (let r = 1; r < m; r++) dp[r][0] = dp[r-1][0] + grid[r][0];for (let c = 1; c < n; c++) dp[0][c] = dp[0][c-1] + grid[0][c];
for (let i = 0; i < m; i++) { dp[i][0] = matrix[i][0] === 1 ? 1 : 0; best = Math.max(best, dp[i][0]); }for (let j = 0; j < n; j++) { dp[0][j] = matrix[0][j] === 1 ? 1 : 0; best = Math.max(best, dp[0][j]); }
// dp[0][0] = 0; all dp[0][i>0] = Infinity (implicit from fill)
for (let i = 1; i < m; i++) dp[i][0] = dp[i-1][0] + grid[i][0];for (let j = 1; j < n; j++) dp[0][j] = dp[0][j-1] + grid[0][j];
// dp[0][0] = 0; all dp[0][i>0] = Infinity (implicit from fill)
// first row and first column stay at 1 (implicit via fill(1))
—
—
—
for (let i = 1; i < m; i++) dp[i][0] = obstacleGrid[i][0] === 1 ? 0 : dp[i-1][0];for (let j = 1; j < n; j++) dp[0][j] = obstacleGrid[0][j] === 1 ? 0 : dp[0][j-1];
for (let i = m - 2; i >= 0; i--) dp[i][n-1] = Math.max(1, dp[i+1][n-1] - dungeon[i][n-1]);for (let j = n - 2; j >= 0; j--) dp[m-1][j] = Math.max(1, dp[m-1][j+1] - dungeon[m-1][j]);
BUILD
for i, j (nested) starting at (1, 1)
for (let i = 1; i < m; i++) {for (let j = 1; j < n; j++) {
—
for (let r = 1; r < m; r++) {for (let c = 1; c < n; c++) {
for (let i = 1; i < m; i++) {for (let j = 1; j < n; j++) {
for (let day = 1; day <= d; day++) {for (let i = day; i <= n; i++) {let maxJob = 0;for (let j = i; j >= day; j--) {
for (let i = 1; i < m; i++) {for (let j = 1; j < n; j++) {
for (let day = 1; day <= days; day++) {for (let i = day; i <= n; i++) {let maxSize = 0;for (let j = i; j >= day; j--) {
for (let r = 1; r < m; r++) {
—
—
—
for (let i = 1; i < m; i++) {for (let j = 1; j < n; j++) {
for (let i = m - 2; i >= 0; i--) {for (let j = n - 2; j >= 0; j--) {
[RECURRENCE]
dp[i][j] = f(dp[i-1][j], dp[i][j-1], grid[i][j])
dp[i][j] = Math.min(grid[i][j], Math.max(dp[i-1][j], dp[i][j-1]));
—
dp[r][c] = grid[r][c] + Math.min(dp[r-1][c], dp[r][c-1]);
if (matrix[i][j] === 1) {dp[i][j] = 1 + Math.min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]);}best = Math.max(best, dp[i][j]);
if (jobs[j - 1] > maxJob) maxJob = jobs[j - 1];if (dp[day - 1][j - 1] !== Infinity) {const candidate = dp[day - 1][j - 1] + maxJob;if (candidate < dp[day][i]) dp[day][i] = candidate;}
dp[i][j] = grid[i][j] + Math.min(dp[i-1][j], dp[i][j-1]);
if (sizes[j - 1] > maxSize) maxSize = sizes[j - 1];if (dp[day - 1][j - 1] !== Infinity) {const candidate = dp[day - 1][j - 1] + maxSize;if (candidate < dp[day][i]) dp[day][i] = candidate;}
dp[r][c] = dp[r - 1][c] + dp[r][c - 1];
—
—
—
if (obstacleGrid[i][j] === 1) {dp[i][j] = 0;} else {dp[i][j] = dp[i-1][j] + dp[i][j-1];}
dp[i][j] = Math.max(1, Math.min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j]);
RETURN
return dp[m-1][n-1]
return dp[m - 1][n - 1];
let best = -Infinity; for (let j = 0; j < n; j++) best = Math.max(best, dp[m-1][j]); return best === -Infinity ? -1 : best;
return dp[m-1][n-1];
return best * best;
return dp[d][n] === Infinity ? -1 : dp[d][n];
return dp[m - 1][n - 1];
return dp[days][n] === Infinity ? -1 : dp[days][n];
return dp[m - 1][n - 1];
—
—
—
return dp[m - 1][n - 1];
return dp[0][0];