Minimum Path Sum - DP Solution

Another DP problem at LeetCode: https://leetcode.com/problems/minimum-path-sum/

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example:
Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.

The hints of DP are clear: problem is asking for a min solution, and the brute-force solution is highly exponential, and since the problem does not specify a boundary for the grid, it might be intractable to do it using brute-force.
DP is a construction approach: instead of thinking like recursion where you think in terms of "base case and induction", think more around a "base case and construction", where you'll construct the solution for 0,1,2,....,n-1,n, and then your final solution is whatever you get for n.
Also keep in mind that (usually) DP will require extra space, in our case here O(n)-space.
With that being said, the solution becomes simple: have a "dp" grid which calculates the best solution thus far for the position dp[r,c]. Build that up until dp[n,m], return that value. O(n)-time. Code is below, cheers, Marcelo.


public class Solution
{
 public int MinPathSum(int[,] grid)
 {
  if (grid == null) return 0;

  int[,] dp = new int[grid.GetLength(0), grid.GetLength(1)];

  //Base
  dp[0, 0] = grid[0, 0];
  for (int r = 1; r < grid.GetLength(0); r++) dp[r, 0] = grid[r, 0] + dp[r - 1, 0];
  for (int c = 1; c < grid.GetLength(1); c++) dp[0, c] = grid[0, c] + dp[0, c - 1];

  //Construction
  for (int r = 1; r < dp.GetLength(0); r++)
   for (int c = 1; c < dp.GetLength(1); c++)
    dp[r, c] = grid[r, c] + Math.Min(dp[r - 1, c], dp[r, c - 1]);

  return dp[dp.GetLength(0) - 1, dp.GetLength(1) - 1];
 }
}

Comments

  1. Looks good, although it's not necessary to have a 2 dimensional matrix for dp, since we only need 2 rows:

    class Solution {
    public:
    int minPathSum(const vector>& grid) {
    if (grid.empty()) return 0;
    vector prev(grid[0].size()+1), current(grid[0].size()+1);
    for (int i = 0; i < grid[0].size(); ++i) prev[i+1] = prev[i] + grid[0][i];
    for (int i = 1; i < grid.size(); ++i) {
    current[0] = prev[1];
    for (int j = 0; j < grid[i].size(); ++j) {
    current[j+1] = grid[i][j] + min(current[j], prev[j+1]);
    }
    swap(prev, current);
    }
    return prev.back();
    }
    };

    ReplyDelete

Post a Comment

Popular posts from this blog

Golang vs. C#: performance characteristics (simple case study)

Claude vs ChatGPT: A Coder's Perspective on LLM Performance

ProjectEuler Problem 719 (some hints, but no spoilers)