class Solution:
def minFallingPathSum(self, matrix):
n = len(matrix)
# Start from the second last row and move upwards
for i in range(n - 2, -1, -1):
for j in range(n):
# For each cell, add the minimum of the three possible cells below
best_below = matrix[i+1][j]
if j > 0:
best_below = min(best_below, matrix[i+1][j-1])
if j < n-1:
best_below = min(best_below, matrix[i+1][j+1])
matrix[i][j] += best_below
return min(matrix[0])
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = n - 2; i >= 0; --i) {
for (int j = 0; j < n; ++j) {
int best_below = matrix[i+1][j];
if (j > 0)
best_below = min(best_below, matrix[i+1][j-1]);
if (j < n-1)
best_below = min(best_below, matrix[i+1][j+1]);
matrix[i][j] += best_below;
}
}
return *min_element(matrix[0].begin(), matrix[0].end());
}
};
class Solution {
public int minFallingPathSum(int[][] matrix) {
int n = matrix.length;
for (int i = n - 2; i >= 0; --i) {
for (int j = 0; j < n; ++j) {
int bestBelow = matrix[i+1][j];
if (j > 0)
bestBelow = Math.min(bestBelow, matrix[i+1][j-1]);
if (j < n-1)
bestBelow = Math.min(bestBelow, matrix[i+1][j+1]);
matrix[i][j] += bestBelow;
}
}
int min = Integer.MAX_VALUE;
for (int num : matrix[0]) {
min = Math.min(min, num);
}
return min;
}
}
var minFallingPathSum = function(matrix) {
const n = matrix.length;
for (let i = n - 2; i >= 0; --i) {
for (let j = 0; j < n; ++j) {
let bestBelow = matrix[i+1][j];
if (j > 0)
bestBelow = Math.min(bestBelow, matrix[i+1][j-1]);
if (j < n-1)
bestBelow = Math.min(bestBelow, matrix[i+1][j+1]);
matrix[i][j] += bestBelow;
}
}
return Math.min(...matrix[0]);
};
You are given a square 2D array matrix
of size n x n
consisting of integers. A falling path starts at any element in the first row and chooses one element from each row, moving down to the next row each time. When moving from row i
to row i+1
, you may only move to the element directly below, or diagonally left/right (i.e., columns j-1
, j
, or j+1
).
Your task is to find the minimum possible sum of a falling path through matrix
.
At first glance, the problem seems to require checking all possible paths from the top row to the bottom, summing their values, and finding the minimum. For a matrix of size n
, there could be up to 3^n
possible paths (since at each step, you have up to 3 choices).
However, this brute-force approach is not efficient for larger matrices. Instead, we can observe that the minimum path sum to a cell in a given row only depends on the minimum path sums to the three possible cells above it. This suggests a dynamic programming approach, where we build up the solution row by row, reusing previously computed results.
By thinking in terms of "what is the minimum cost to reach this cell?", we can optimize away redundant calculations and avoid recomputing the same subproblems.
matrix
as our DP table. Each cell matrix[i][j]
will represent the minimum falling path sum to reach cell (i, j)
from the top row.This approach ensures we only compute each subproblem once, and each cell's value accumulates the minimum path sum up to that point. The solution is both efficient and easy to implement.
Consider the following matrix:
[2, 1, 3] [6, 5, 4] [7, 8, 9]
i = 1
):
matrix[1][0]
: possible next cells are matrix[2][0]
and matrix[2][1]
(values 7 and 8). Minimum is 7. Update: 6 + 7 = 13
.matrix[1][1]
: possible next cells are matrix[2][0]
, matrix[2][1]
, matrix[2][2]
(values 7, 8, 9). Minimum is 7. Update: 5 + 7 = 12
.matrix[1][2]
: possible next cells are matrix[2][1]
, matrix[2][2]
(values 8, 9). Minimum is 8. Update: 4 + 8 = 12
.Now the matrix is:
[2, 1, 3] [13, 12, 12] [7, 8, 9]
i = 0
):
matrix[0][0]
: next cells are matrix[1][0]
, matrix[1][1]
(13, 12). Minimum is 12. Update: 2 + 12 = 14
.matrix[0][1]
: next cells are matrix[1][0]
, matrix[1][1]
, matrix[1][2]
(13, 12, 12). Minimum is 12. Update: 1 + 12 = 13
.matrix[0][2]
: next cells are matrix[1][1]
, matrix[1][2]
(12, 12). Minimum is 12. Update: 3 + 12 = 15
.Now the matrix is:
[14, 13, 15] [13, 12, 12] [7, 8, 9]
n
rows: O(3^n)
. This quickly becomes infeasible for large n
.
n x n
cells, and each update takes O(1)
time.O(n^2)
O(1)
extra space if we modify the input matrix in-place, or O(n^2)
if we use a separate DP table.The Minimum Falling Path Sum problem is a classic example of dynamic programming applied to grid traversal. By recognizing overlapping subproblems and using a bottom-up approach, we avoid redundant work and achieve a much faster solution than brute-force. The key insight is that the minimum path sum to each cell depends only on the minimum path sums to the three possible cells above it, which allows for an elegant and efficient solution.