Minimum Path Sum II in JavaScript (O(n * m) Time Complexity)


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.

Note:

Convert the previous solution to an iterative one. Your algorithm should run in O(n * m) time and use O(n * m) extra space.


Understanding the Problem

The core challenge of this problem is to find the path from the top-left corner to the bottom-right corner of a grid that results in the minimum sum of the numbers along the path. The constraints are that you can only move either down or right at any point in time.

This problem is significant in various applications such as robotics (finding the shortest path in a grid), game development (pathfinding algorithms), and operations research (optimizing routes).

Potential pitfalls include misunderstanding the movement constraints and not properly handling the grid boundaries.

Approach

To solve this problem, we can use dynamic programming. The idea is to create a 2D array (dp) where each cell dp[i][j] represents the minimum path sum to reach that cell from the top-left corner.

We can start by initializing the top-left cell with the value of the grid's top-left cell. Then, we iterate through the grid, updating each cell in the dp array with the minimum sum to reach that cell.

Initially, a naive solution might involve recursively exploring all possible paths, but this would be highly inefficient with a time complexity of O(2^(n+m)). Instead, we use dynamic programming to reduce the time complexity to O(n * m).

Algorithm

1. Create a 2D array dp with the same dimensions as the grid.

2. Initialize the top-left cell of dp with the value of the top-left cell of the grid.

3. Iterate through the grid, updating each cell in dp with the minimum sum to reach that cell.

4. The value in the bottom-right cell of dp will be the minimum path sum.

Code Implementation

/**
 * @param {number[][]} grid
 * @return {number}
 */
function minPathSum(grid) {
    const m = grid.length;
    const n = grid[0].length;
    
    // Create a 2D array to store the minimum path sums
    const dp = Array.from({ length: m }, () => Array(n).fill(0));
    
    // Initialize the top-left cell
    dp[0][0] = grid[0][0];
    
    // Fill the first row
    for (let j = 1; j < n; j++) {
        dp[0][j] = dp[0][j - 1] + grid[0][j];
    }
    
    // Fill the first column
    for (let i = 1; i < m; i++) {
        dp[i][0] = dp[i - 1][0] + grid[i][0];
    }
    
    // Fill the rest of the dp array
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
        }
    }
    
    // The bottom-right cell contains the minimum path sum
    return dp[m - 1][n - 1];
}

// Example usage:
const grid = [
    [1, 3, 1],
    [1, 5, 1],
    [4, 2, 1]
];
console.log(minPathSum(grid)); // Output: 7

Complexity Analysis

The time complexity of this solution is O(n * m) because we iterate through each cell of the grid once. The space complexity is also O(n * m) due to the additional 2D array used to store the minimum path sums.

Edge Cases

Potential edge cases include:

Examples:

// Edge case: Empty grid
console.log(minPathSum([])); // Output: 0

// Edge case: Single row grid
console.log(minPathSum([[1, 2, 3]])); // Output: 6

// Edge case: Single column grid
console.log(minPathSum([[1], [2], [3]])); // Output: 6

Testing

To test the solution comprehensively, we should include a variety of test cases, from simple to complex. We can use testing frameworks like Jest or Mocha for automated testing.

Example test cases:

const assert = require('assert');

// Test case 1: Example grid
assert.strictEqual(minPathSum([
    [1, 3, 1],
    [1, 5, 1],
    [4, 2, 1]
]), 7);

// Test case 2: Empty grid
assert.strictEqual(minPathSum([]), 0);

// Test case 3: Single row grid
assert.strictEqual(minPathSum([[1, 2, 3]]), 6);

// Test case 4: Single column grid
assert.strictEqual(minPathSum([[1], [2], [3]]), 6);

console.log('All test cases pass');

Thinking and Problem-Solving Tips

When approaching such problems, it's essential to break down the problem into smaller subproblems and think about how to solve each subproblem efficiently. Dynamic programming is a powerful technique for optimizing recursive solutions by storing intermediate results.

To develop problem-solving skills, practice solving similar problems and study various algorithms. Platforms like LeetCode, HackerRank, and CodeSignal offer a wide range of problems to practice.

Conclusion

In this blog post, we discussed how to solve the "Minimum Path Sum II" problem using dynamic programming. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving problem-solving skills and preparing for technical interviews.

Keep practicing and exploring further to enhance your skills!

Additional Resources