Minimum Path Sum

Find the optimal path through a grid using dynamic programming to minimize the sum of values along the path

Algorithm Overview

Key Characteristics

  • Dynamic Programming: Optimal subproblem structure
  • Space Optimized: O(n) memory using 1D DP array
  • In-place Updates: Efficient memory utilization
  • Bottom-up Approach: Builds solution incrementally

Why This Algorithm?

  • Optimal Time: O(m×n) - visits each cell once
  • Memory Efficient: O(n) vs O(m×n) for naive 2D DP
  • Cache Friendly: Sequential memory access pattern
  • Production Ready: Handles edge cases robustly

Example 1

Input:
[[1,3,1],
[1,5,1],
[4,2,1]]
Output:
7

Path: 1→3→1→1→1

Example 2

Input:
[[1,2,3],
[4,5,6]]
Output:
12

Path: 1→2→3→6

Interactive Algorithm Demonstration

Algorithm Steps

1

Initialize DP Array

Create a 1D array dp[] of size n and initialize the first row with cumulative sums.

2

Process First Column

For each row, update dp[0] by adding the current cell value to represent the cumulative sum down the first column.

3

Calculate Minimum Path

For each cell, choose the minimum between coming from top (dp[j]) or left (dp[j-1]) and add current cell value.

4

Update Row by Row

Process each row left to right, updating dp[] array in-place with optimal path sums.

5

Return Final Result

The last element dp[n-1] contains the minimum path sum from top-left to bottom-right.

Visualization

Initial Grid

Original grid with values

1
3
1
1
5
1
4
2
1

Implementation Code

Python - LeetCode Solution

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        """
        Find minimum path sum from top-left to bottom-right.
        Time: O(m*n), Space: O(n) - optimized 1D DP
        """
        m, n = len(grid), len(grid[0])

        # Edge case optimization
        if m == 1 and n == 1:
            return grid[0][0]

        # Initialize 1D DP array with first row
        dp = [0] * n
        dp[0] = grid[0][0]

        # Fill first row with cumulative sums
        for j in range(1, n):
            dp[j] = dp[j - 1] + grid[0][j]

        # Process remaining rows
        for i in range(1, m):
            # Update first column (can only come from above)
            dp[0] += grid[i][0]

            # Update remaining columns (min of top or left)
            for j in range(1, n):
                dp[j] = min(dp[j], dp[j - 1]) + grid[i][j]

        return dp[n - 1]

Key Optimizations

  • Space Optimized: Uses O(n) instead of O(m×n)
  • In-place Updates: Reuses dp array efficiently
  • Edge Case: Early return for 1×1 grids

Algorithm Details

  • DP Recurrence: dp[j] = min(dp[j], dp[j-1]) + grid[i][j]
  • Initialization: First row filled with cumulative sums
  • Update Order: Left to right, top to bottom

Algorithm Flow Diagram

START Initialize dp array dp = [grid[0][0]] Fill first row dp[j] = dp[j-1] + grid[0][j] For each row i (1 to m-1) Process row by row Update first column dp[0] += grid[i][0] For each column j (1 to n-1) Calculate min path dp[j] = min(dp[j], dp[j-1]) + grid[i][j] Return dp[n-1] Minimum path sum

Initialization Phase

Create 1D DP array and fill the first row with cumulative sums. This represents the minimum cost to reach each position in the first row.

Processing Phase

For each subsequent row, update the DP array by choosing the minimum cost path (from top or left) and adding the current cell value.

Completion Phase

After processing all rows, dp[n-1] contains the minimum path sum from the top-left to bottom-right corner of the grid.

Complexity Analysis

Time Complexity

O(m × n)
  • Visit each cell exactly once
  • Constant time operations per cell
  • Linear scan for initialization

Space Complexity

O(n)
  • 1D DP array of size n
  • In-place updates save memory
  • No additional data structures

Algorithm Comparison

Approach Time Space Pros Cons
1D DP (Optimal) O(m×n) O(n) Memory efficient, cache-friendly Slightly complex logic
2D DP O(m×n) O(m×n) Intuitive, easy to understand High memory usage
In-place DP O(m×n) O(1) Minimal memory Destroys input, not always allowed
Recursive + Memo O(m×n) O(m×n) Natural problem mapping Stack overflow risk, slower

Why This Algorithm Is Optimal

Performance

Achieves optimal O(m×n) time complexity while minimizing space usage to O(n)

Cache Friendly

Sequential memory access pattern improves cache performance on modern processors

Balanced

Perfect balance between time efficiency, space optimization, and code maintainability