101 Logo
onenoughtone

Solution Approach

Solution Overview

There are 3 main approaches to solve this problem:

  1. Dynamic Programming (2D) - Complex approach
  2. Dynamic Programming (1D) - Complex approach
  3. In-place Dynamic Programming - Complex approach

Approach 1: Dynamic Programming (2D)

The key insight for solving this problem is to use dynamic programming to build up the solution from smaller subproblems.

Let's define dp[i][j] as the minimum path sum to reach the cell at position (i, j) from the top-left corner (0, 0).

Since we can only move right or down, to reach the cell (i, j), we must come from either the cell above it (i-1, j) or the cell to its left (i, j-1). Therefore, the recurrence relation is:

dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])

For the base cases:

  • dp[0][0] = grid[0][0] (the top-left cell)
  • For the first row (i = 0), dp[0][j] = grid[0][j] + dp[0][j-1] (we can only come from the left)
  • For the first column (j = 0), dp[i][0] = grid[i][0] + dp[i-1][0] (we can only come from above)

The final answer is dp[m-1][n-1], which represents the minimum path sum to reach the bottom-right corner.

Algorithm:

  1. Initialize a 2D DP array dp of size m × n, where dp[i][j] represents the minimum path sum to reach the cell at position (i, j).
  2. Set the base case: dp[0][0] = grid[0][0].
  3. For the first row (i = 0), set dp[0][j] = grid[0][j] + dp[0][j-1] for all j from 1 to n-1.
  4. For the first column (j = 0), set dp[i][0] = grid[i][0] + dp[i-1][0] for all i from 1 to m-1.
  5. For each cell (i, j) where i > 0 and j > 0, calculate dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]).
  6. Return dp[m-1][n-1], which represents the minimum path sum to reach the bottom-right corner.

Time Complexity:

O(m * n)

We need to fill in the DP table of size m × n, and each cell takes constant time to compute.

Space Complexity:

O(m * n)

We use a 2D DP array of size m × n to store the minimum path sum for each cell.

Approach 2: Dynamic Programming (1D)

We can optimize the space complexity of the dynamic programming approach by using a 1D array instead of a 2D array.

The key observation is that when we're calculating dp[i][j], we only need the values from the current row and the row above it. Specifically, we need dp[i-1][j] and dp[i][j-1].

If we use a 1D array dp where dp[j] represents the minimum path sum to reach the cell at position (i, j), then:

  • Before the update, dp[j] represents the minimum path sum to reach the cell at position (i-1, j).
  • After updating dp[j-1], dp[j-1] represents the minimum path sum to reach the cell at position (i, j-1).

So, the recurrence relation becomes:

dp[j] = grid[i][j] + min(dp[j], dp[j-1])

We need to be careful with the first column (j = 0), as there is no cell to its left. For the first column, we simply update dp[0] = dp[0] + grid[i][0].

The final answer is dp[n-1], which represents the minimum path sum to reach the bottom-right corner.

Algorithm:

  1. Initialize a 1D DP array dp of size n, where dp[j] represents the minimum path sum to reach the cell at position (0, j) in the first row.
  2. Set the base case: dp[0] = grid[0][0].
  3. For the first row (i = 0), set dp[j] = grid[0][j] + dp[j-1] for all j from 1 to n-1.
  4. For each row i from 1 to m-1:
  5. a. Update dp[0] = dp[0] + grid[i][0] (for the first column).
  6. b. For each column j from 1 to n-1:
  7. i. Update dp[j] = grid[i][j] + min(dp[j], dp[j-1]).
  8. Return dp[n-1], which represents the minimum path sum to reach the bottom-right corner.

Time Complexity:

O(m * n)

We still need to process each cell in the grid, which takes O(m * n) time.

Space Complexity:

O(n)

We only use a 1D array of size n to store the minimum path sum for the current row.

Approach 3: In-place Dynamic Programming

We can further optimize the space complexity by modifying the input grid in-place to store the minimum path sum for each cell.

The recurrence relation remains the same:

grid[i][j] = grid[i][j] + min(grid[i-1][j], grid[i][j-1])

We need to be careful with the base cases:

  • For the first row (i = 0), grid[0][j] = grid[0][j] + grid[0][j-1] for all j from 1 to n-1.
  • For the first column (j = 0), grid[i][0] = grid[i][0] + grid[i-1][0] for all i from 1 to m-1.

The final answer is grid[m-1][n-1], which represents the minimum path sum to reach the bottom-right corner.

Note that this approach modifies the input grid, which might not be desirable in all situations. If preserving the input is important, we should use one of the previous approaches.

Algorithm:

  1. For the first row (i = 0), set grid[0][j] = grid[0][j] + grid[0][j-1] for all j from 1 to n-1.
  2. For the first column (j = 0), set grid[i][0] = grid[i][0] + grid[i-1][0] for all i from 1 to m-1.
  3. For each cell (i, j) where i > 0 and j > 0, calculate grid[i][j] = grid[i][j] + min(grid[i-1][j], grid[i][j-1]).
  4. Return grid[m-1][n-1], which represents the minimum path sum to reach the bottom-right corner.

Time Complexity:

O(m * n)

We still need to process each cell in the grid, which takes O(m * n) time.

Space Complexity:

O(1)

We modify the input grid in-place, so we don't need any additional space beyond the input.

Pseudocode

solution.pseudo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function minPathSum(grid):
m = grid.length
n = grid[0].length
// Initialize DP array
dp = new 2D array of size m × n
// Set base case for top-left cell
dp[0][0] = grid[0][0]
// Set base cases for first row
for j from 1 to n-1:
dp[0][j] = grid[0][j] + dp[0][j-1]
// Set base cases for first column
for i from 1 to m-1:
dp[i][0] = grid[i][0] + dp[i-1][0]
// Fill DP array
for i from 1 to m-1:
for j from 1 to n-1:
dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
return dp[m-1][n-1]
ProblemSolutionCode
101 Logo
onenoughtone