LeetCode #64 Medium

Minimum Path Sum

Cheapest top-left → bottom-right path in a grid of non-negative costs, moving only right or down.

dpgrid
Open on LeetCode ↗
02

Intuition

You can only arrive at a cell from above or from the left, so the cheapest way to reach it is its own cost plus the cheaper of those two arrivals. Fill the grid in reading order and every cell's answer is ready when you need it — the bottom-right cell ends up holding the global minimum.

How to spot this pattern

Grid DP where movement is right-and-down only, so every cell depends solely on cells already computed — one sweep in reading order, no recursion. Because each cell is read exactly twice after being written, you can accumulate straight into the input grid and use no extra memory at all.

03

Approach

1

State and transition

dp[r][c] = min cost to reach (r,c) = grid[r][c] + min(dp[r-1][c], dp[r][c-1]).

2

Edges are forced

Top row can only come from the left, first column only from above — running prefix sums, no min needed.

3

In-place fill

Overwrite the grid itself: no extra memory, and the traversal order (row by row) guarantees dependencies are computed first.

04

Solution & live demo

1class Solution:
2 def minPathSum(self, grid):
3 R, C = len(grid), len(grid[0])
4 for r in range(R):
5 for c in range(C):
6 if r == 0 and c == 0: continue
7 if r == 0: grid[r][c] += grid[r][c-1]
8 elif c == 0: grid[r][c] += grid[r-1][c]
9 else: grid[r][c] += min(grid[r-1][c], grid[r][c-1])
10 return grid[-1][-1]
05

Common pitfalls

Handling the first row and column inside the general case

✗ Wrong
grid[r][c] += min(grid[r-1][c], grid[r][c-1])
✓ Right
if r == 0:   grid[r][c] += grid[r][c-1]
elif c == 0: grid[r][c] += grid[r-1][c]
else:        grid[r][c] += min(grid[r-1][c], grid[r][c-1])

On the top row grid[r-1][c] is grid[-1][c], which Python happily reads from the bottom row instead of erroring — you silently mix in values from the far edge of the grid. Edges have only one predecessor and must be treated separately.

Overwriting the starting cell

✗ Wrong
for r in range(R):
    for c in range(C):
        grid[r][c] += ...
✓ Right
if r == 0 and c == 0: continue

The origin is its own base case — the cost of reaching it is just its value. Adding anything to it double-counts the start and shifts every path total.

Taking the max instead of the min

✗ Wrong
grid[r][c] += max(grid[r-1][c], grid[r][c-1])
✓ Right
grid[r][c] += min(grid[r-1][c], grid[r][c-1])

The recurrence direction is the whole difference between this problem and its maximise-the-sum sibling. Both compile and run; only one answers the question asked.

06

Edge cases

Single cell

Answer is grid[0][0] itself.

Single row or column

Forced path — plain sum, handled by the edge initialization.

Greedy fails

Always taking the locally cheaper step can miss a cheap corridor later — that's why DP, not greedy.

07

Complexity

Time
O(R·C)
Space
O(1)
Grid reused as the DP table.