Minimum Falling Path Sum II

Updated on 13 June, 2025
Minimum Falling Path Sum II header image

Problem Statement

In this problem, you are provided with an n x n integer matrix named grid. Your task is to compute the minimum sum of a unique type of falling path called a falling path with non-zero shifts. Each falling path must select exactly one element from each row such that no chosen elements in subsequent rows share the same column location. The output should be an integer representing the minimum sum of such a path through the matrix adhering to these constraints.

Examples

Example 1

Input:

grid = [[1,2,3],[4,5,6],[7,8,9]]

Output:

13

Explanation:

The possible falling paths are:
[1,5,9], [1,5,7], [1,6,7], [1,6,8],
[2,4,8], [2,4,9], [2,6,7], [2,6,8],
[3,4,8], [3,4,9], [3,5,7], [3,5,9]
The falling path with the smallest sum is [1,5,7], so the answer is 13.

Example 2

Input:

grid = [[7]]

Output:

7

Constraints

  • n == grid.length == grid[i].length
  • 1 <= n <= 200
  • -99 <= grid[i][j] <= 99

Approach and Intuition

Understanding the approach and intuition behind solving this problem can be broken down into several key points:

  1. Falling Path with Non-Zero Shifts Defined:

    • A falling path starts from any element in the first row and moves down to the last row.
    • For any element selected in row i, the element selected from row i+1 must be from a different column.
    • This ensures no two consecutive rows have elements from the same column in the path.
  2. Dynamic Programming Approach:

    • Iterate through each row of the matrix and maintain a record of the minimum path sum to reach each element from any column in the previous row without repeating columns.
    • Start with the first row where the initial path sums are just the values of the elements themselves.
    • For each subsequent row and for each column, compute the cost by adding the matrix value to the minimum of the path sums from the last row from permissible columns.
  3. Choosing the Optimal Path:

    • The optimal path through the matrix is the one which results in the minimum sum at the end of the last row after considering all the constraints.
    • Scanning through the values accumulated in the last row gives us our answer.
  4. Efficient Calculation:

    • Avoid recalculating minimum values for permissible columns by keeping track of minima in the previous iterations efficiently.
    • This ensures that the time complexity stays manageable even for the largest size constraints.
  5. Complexity Considerations:

    • The naive approach would involve considering all possible paths, which would be computationally expensive.
    • Dynamic programming provides a polynomial time solution, as for each row, the minimum path from the previous row needs to be calculated for each column.
    • This results in a time complexity of approximately O(n^3) for each matrix where n is the number of rows/columns. However, optimizations in step management could potentially reduce the computational overhead.

In summary, this problem can be tackled effectively using a dynamic programming approach where you use past computed values to iteratively determine the minimum path sum for the current row considering the non-zero shift constraint. This intuition leverages past computation for efficient future operations enhancing both performance and understanding of the problem's nature.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    int minimalFallingPathSum(vector<vector<int>>& matrix) {
        // Indices for minimum and second minimum values in a row
        int minIdx1 = -1, minIdx2 = -1;

        // Values of minimum and second minimum element in each row
        int minValue1 = -1, minValue2 = -1;

        // Initialize the last row's minimum values and their indices
        for (int j = 0; j < matrix.size(); j++) {
            if (minValue1 == -1 || matrix.back()[j] <= minValue1) {
                minValue2 = minValue1;
                minIdx2 = minIdx1;
                minValue1 = matrix.back()[j];
                minIdx1 = j;
            } else if (minValue2 == -1 || matrix.back()[j] <= minValue2) {
                minValue2 = matrix.back()[j];
                minIdx2 = j;
            }
        }

        // Process rows from bottom to top
        for (int i = matrix.size() - 2; i >= 0; i--) {
            // Current row's minimum values and their indices
            int currentMin1 = -1, currentMin2 = -1;
            int currentIdx1 = -1, currentIdx2 = -1;

            for (int j = 0; j < matrix.size(); j++) {
                int addedValue;
                // Apply the respective minimum depending on index conflict
                if (j != minIdx1) {
                    addedValue = matrix[i][j] + minValue1;
                } else {
                    addedValue = matrix[i][j] + minValue2;
                }

                // Determine new minimums for the current row
                if (currentMin1 == -1 || addedValue <= currentMin1) {
                    currentMin2 = currentMin1;
                    currentIdx2 = currentIdx1;
                    currentMin1 = addedValue;
                    currentIdx1 = j;
                } else if (currentMin2 == -1 || addedValue <= currentMin2) {
                    currentMin2 = addedValue;
                    currentIdx2 = j;
                }
            }

            // Update values for the next iteration (up the matrix)
            minValue1 = currentMin1, minValue2 = currentMin2;
            minIdx1 = currentIdx1, minIdx2 = currentIdx2;
        }

        // The minimal falling path sum from top to bottom
        return minValue1;
    }
};

The provided C++ solution efficiently calculates the minimum falling path sum for a square matrix where from element matrix[i][j], one can move to matrix[i-1][j] only if j differs from the column of the minimum element selected from the previous row.

The algorithm makes use of dynamic programming with the following steps:

  1. Initialize variables to capture the indices (minIdx1, minIdx2) and values (minValue1, minValue2) of the smallest and second smallest elements in the current row, starting from the last row of the matrix.
  2. For each cell in the last row, determine where it fits in the current scheme of minimum and second minimum.
  3. From the second last row to the first, iterate over each row and calculate the potential falling path sum for each element using the minimum values from the row directly below. This ensures that no two selected elements are in the same column unless necessary.
  4. While iterating through each row, update the values of minValue1, minValue2 and their respective indices minIdx1, minIdx2 for use in the next row iteration.
  5. At the end of iterations, minValue1 contains the minimum falling path sum from top to bottom of the matrix.

This method ensures an optimized solution by avoiding recalculations and only considering valid paths, thereby handling the constraint effectively that one should not fall vertically down from one row to the next. The space required is O(1) beyond the input matrix, with computation time efficiently managed through continuous updates within single-row scans.

java
class Solution {
    public int minimumFallingPathSum(int[][] matrix) {
        // Initialize variables for tracking minimums and indices
        int prevMinIndex = -1;
        int prevSecondMinIndex = -1;
        int prevMin = -1;
        int prevSecondMin = -1;

        // Identify the minimum and second minimum from the bottom-most row
        for (int col = 0; col < matrix.length; col++) {
            if (prevMin == -1 || matrix[matrix.length - 1][col] <= prevMin) {
                prevSecondMin = prevMin;
                prevSecondMinIndex = prevMinIndex;
                prevMin = matrix[matrix.length - 1][col];
                prevMinIndex = col;
            } else if (prevSecondMin == -1 || matrix[matrix.length - 1][col] <= prevSecondMin) {
                prevSecondMin = matrix[matrix.length - 1][col];
                prevSecondMinIndex = col;
            }
        }

        // Process each row starting from second to last
        for (int row = matrix.length - 2; row >= 0; row--) {
            // Temporary storage for minimums of the current row
            int curMinIndex = -1;
            int curSecondMinIndex = -1;
            int curMin = -1;
            int curSecondMin = -1;

            for (int col = 0; col < matrix.length; col++) {
                // Compute current cost based on whether the column is the previous minimum index
                int currentCost = matrix[row][col] + (col != prevMinIndex ? prevMin : prevSecondMin);

                // Track current row's minimums
                if (curMin == -1 || currentCost <= curMin) {
                    curSecondMin = curMin;
                    curSecondMinIndex = curMinIndex;
                    curMin = currentCost;
                    curMinIndex = col;
                } else if (curSecondMin == -1 || currentCost <= curSecondMin) {
                    curSecondMin = currentCost;
                    curSecondMinIndex = col;
                }
            }

            // Update for the next iteration (next upper row)
            prevMinIndex = curMinIndex;
            prevSecondMinIndex = curSecondMinIndex;
            prevMin = curMin;
            prevSecondMin = curSecondMin;
        }

        // The minimum path sum at the top row
        return prevMin;
    }
}

To find the Minimum Falling Path Sum II in a matrix, follow this approach in Java:

  1. Initialize variables to store the indices and values of the smallest and second smallest elements from each row. Start from the bottom-most row to determine these initial values.

  2. For each row, starting from the second-to-last and moving upwards, use the values from the row below to determine the minimum path sum.

    • Calculate the potential new path sum for each column in the current row by adding the matrix value to the previous row's minimum path sums. Ensure that the column indices do not repeat by choosing the second smallest sum if it's the same column as before.
    • Update the current smallest and second smallest sums and their respective indices.
  3. After processing all rows, the variable storing the minimum sum will contain the result, which represents the minimum falling path sum that can be achieved from top to bottom.

The Java code provided dynamically analyzes each row in the matrix while ensuring that each step in the path minimally increases the sum, efficiently handling the problem without the need for excessive branching or nested loops. It effectively leverages dynamic programming principles with optimization techniques to keep track of necessary indices and values.

python
class Solution:
    def minimumFallingPathSum(self, matrix: List[List[int]]) -> int:
        # Establishing the length of the matrix
        size = len(matrix)

        # Starting positions and values
        minCol1 = minCol2 = None
        minVal1 = minVal2 = None

        # Initialize minimum and second minimum in the last row
        for col in range(size):
            if minVal1 is None or matrix[size - 1][col] <= minVal1:
                minVal2 = minVal1
                minCol2 = minCol1
                minVal1 = matrix[size - 1][col]
                minCol1 = col
            elif minVal2 is None or matrix[size - 1][col] < minVal2:
                minVal2 = matrix[size - 1][col]
                minCol2 = col

        # Process each row from bottom to top
        for row in range(size - 2, -1, -1):
            currentMinCol1 = currentMinCol2 = None
            currentMinVal1 = currentMinVal2 = None

            for col in range(size):
                # Calculate new path sum not using the same column unless necessary
                if col != minCol1:
                    cost = matrix[row][col] + minVal1
                else:
                    cost = matrix[row][col] + minVal2

                # Update the local minima for the current row
                if currentMinVal1 is None or cost <= currentMinVal1:
                    currentMinVal2 = currentMinVal1
                    currentMinCol2 = currentMinCol1
                    currentMinVal1 = cost
                    currentMinCol1 = col
                elif currentMinVal2 is None or cost < currentMinVal2:
                    currentMinVal2 = cost
                    currentMinCol2 = col

            # Prepare for the next iteration by updating minima
            minCol1, minCol2 = currentMinCol1, currentMinCol2
            minVal1, minVal2 = currentMinVal1, currentMinVal2

        # The result is the minimum value for the top row
        return minVal1

In the provided Python code, you explore a dynamic programming solution to the problem of finding the minimum falling path sum through a matrix. This specific version of the problem does not allow the reuse of the same column index for consecutive rows unless it's necessary due to costs.

Here's a breakdown of how the code tackles this problem:

  • Initialization: Start by defining the matrix size and initializing variables to track the minimum (minVal1, minCol1) and the second minimum values (minVal2, minCol2) in the last row of the matrix.

  • Base Case Setup: Iterate through the last row to establish the minimum and second minimum values which will serve as the base for calculating the costs of paths ending in each column of the row above.

  • Dynamic Calculation: Iterate from the second last row up to the first row. For each element in a row, decide the cost of reaching that element by adding its value to the minimum value of the previous row, taking care to adjust if the minimum comes from the same column. Update local minima for current processing row accordingly.

  • Decision Making: For each column in a row, compute the cost. If the current column was the column of the minimum value in the row below (minCol1), then the alternative path through the second minimum (minVal2) is considered. This ensures the path does not fall through the same column unless absolutely necessary to minimize the path sum.

  • Update Local and Global Minima: After processing each row, update the global minimum trackers (minCol1, minCol2, minVal1, and minVal2) with the local minimum trackers to carry forward to the next iteration.

  • Result Extraction: After all rows are processed, minVal1 represents the minimum path sum from the top to the bottom of the matrix avoiding vertical paths through the same column consecutively unless needed.

This dynamic programming approach ensures an efficient computation by continuously updating possible minimum paths for each row, making it adaptable to matrices of various sizes while ensuring optimal runtime and complexity.

Comments

No comments yet.