Loading problems...
TL;DR: The optimal solution utilizes a 2D Dynamic Programming approach to calculate the minimum cumulative cost to reach every cell by comparing the costs of arriving from the top versus the left.
The Minimum Path Sum problem asks us to find a path through a grid of non-negative integers from the top-left corner (0, 0) to the bottom-right corner (m-1, n-1). The objective is to minimize the sum of all numbers along the path. The constraint on movement is strict: from any given cell, you may only move strictly down or strictly right. This is a classic optimization problem found in LeetCode 64.
The brute force strategy involves exploring every possible path from the start to the destination to determine which one yields the lowest sum. Since movement is restricted to down and right, this can be modeled as a recursive depth-first search.
At any cell (i, j), the cost to reach the destination is the value of the current cell plus the minimum cost to reach the destination from either the right neighbor (i, j+1) or the bottom neighbor (i+1, j).
textfunction solve(i, j): if i or j is out of bounds: return infinity if i is last row and j is last col: return grid[i][j] move_right = solve(i, j + 1) move_down = solve(i + 1, j) return grid[i][j] + min(move_right, move_down)
The time complexity of this approach is O(2^(m+n)).
Because each cell generates two recursive branches, and the path length is m + n, the recursion tree grows exponentially.
This approach fails due to overlapping subproblems. The algorithm re-calculates the minimum path for the same cells millions of times. For a grid of size , the number of operations exceeds the computational limits, resulting in a Time Limit Exceeded (TLE) error.
The key intuition for solving LeetCode 64 efficiently lies in the direction of movement. Since we can only move down or right, a cell at position (i, j) can only be reached from:
(i-1, j)(i, j-1)This implies that the minimum path sum to reach (i, j) is the value in grid[i][j] plus the smaller of the two cumulative sums calculated for (i-1, j) and (i, j-1).
This creates a recurrence relation:
By solving this iteratively starting from (0, 0), we build a table where every entry represents the global minimum cost to reach that specific coordinate. This eliminates redundant calculations found in the brute force method.
Visual Description: Imagine the grid being filled cell by cell, row by row.

The strategy employs an iterative bottom-up Dynamic Programming approach. We can either use a separate dp table of the same dimensions as the grid or, to save space, modify the input grid in-place.
(0, 0) is the base cost.(0, j) is updated to grid[0][j] + grid[0][j-1]. This is because the only way to reach a cell in the first row is from the left.(i, 0) is updated to grid[i][0] + grid[i-1][0]. This is because the only way to reach a cell in the first column is from above.(1, 1) to (m-1, n-1).(i, j), update its value to be the current value plus the minimum of the value above it and the value to its left.(m-1, n-1) will contain the minimum path sum.m (rows) and n (cols).j = 1 to n-1. Update grid[0][j] += grid[0][j-1].i = 1 to m-1. Update grid[i][0] += grid[i-1][0].i from 1 to m-1.j from 1 to n-1.min_prev = min(grid[i-1][j], grid[i][j-1]).grid[i][j] += min_prev.grid[m-1][n-1].The correctness relies on the Principle of Optimality.
(0,0) is trivially correct (cost is grid[0][0]).(x, y) where x < i or y < j, the algorithm has correctly computed the minimum path sum. To compute the optimal path to (i, j), the path must arrive from either (i-1, j) or (i, j-1). Since grid[i][j] is non-negative and we select the minimum of the two optimal predecessors, the sum at (i, j) is guaranteed to be minimal.(m-1, n-1) is the global minimum.cppclass Solution { public: int minPathSum(vector<vector<int>>& grid) { if (grid.empty() || grid[0].empty()) return 0; int m = grid.size(); int n = grid[0].size(); // Initialize first row (can only come from left) for (int j = 1; j < n; ++j) { grid[0][j] += grid[0][j - 1]; } // Initialize first column (can only come from up) for (int i = 1; i < m; ++i) { grid[i][0] += grid[i - 1][0]; } // Fill the rest of the grid for (int i = 1; i < m; ++i) { for (int j = 1; j < n; ++j) { // Current cell cost + min(top, left) grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]); } } return grid[m - 1][n - 1]; } };
javaclass Solution { public int minPathSum(int[][] grid) { if (grid == null || grid.length == 0) return 0; int m = grid.length; int n = grid[0].length; // Initialize first row (accumulate sums from left) for (int j = 1; j < n; j++) { grid[0][j] += grid[0][j - 1]; } // Initialize first column (accumulate sums from top) for (int i = 1; i < m; i++) { grid[i][0] += grid[i - 1][0]; } // Process the inner cells for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { // The cost is current value + min of top or left neighbor grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]); } } return grid[m - 1][n - 1]; } }
pythonclass Solution: def minPathSum(self, grid: List[List[int]]) -> int: if not grid: return 0 m, n = len(grid), len(grid[0]) # Initialize first row (accumulate sums from left) for j in range(1, n): grid[0][j] += grid[0][j - 1] # Initialize first column (accumulate sums from top) for i in range(1, m): grid[i][0] += grid[i - 1][0] # Process the inner cells for i in range(1, m): for j in range(1, n): # Update current cell with min path from top or left grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]) return grid[m - 1][n - 1]
Time Complexity: We iterate through every cell in the grid exactly once. The operations inside the loop (addition and finding the minimum) are constant time . Thus, the total time is proportional to the number of elements in the grid.
Space Complexity:
By modifying the input grid in-place to store the DP states, we avoid allocating additional data structures. If modifying the input is not allowed, we would allocate a separate 2D array, resulting in space, or optimize further to by storing only the current and previous rows. The provided solution uses the in-place approach for maximum efficiency.
The DP - 2D Array pattern used here is fundamental to several other LeetCode problems. Understanding the state transition from top/left neighbors applies directly to:
Why does my recursive solution get Time Limit Exceeded?
Why is my answer wrong for grids with only one row or column?
i-1 and j-1. If you apply the general formula min(grid[i-1][j], grid[i][j-1]) to the first row (where i=0), you will access out-of-bounds memory or incorrect logic.Can I use a Greedy approach (always pick the smallest neighbor)?
100 might lead to a path of 1s, while a cell of 1 might lead to a path of 100s.