931. Minimum Falling Path Sum
On LeetCode ->Problem¶
Given an \(n \times n\) integer matrix, find the minimum sum of a path that starts anywhere in the first row and moves to the next row in the same column or one column left or right.
Key trick¶
Use row-by-row dynamic programming: the minimum path to each cell depends only on the three reachable cells from the previous row.
Trap¶
Updating a single DP array carelessly can overwrite values still needed for neighboring cells; also handle the left and right boundaries correctly.
Why is it interesting?¶
It reduces a two-dimensional path problem to one-dimensional dynamic programming.
Python solution¶
class Solution:
def minFallingPathSum(self, matrix: list[list[int]]) -> int:
n = len(matrix)
# dp[c] is the minimum sum of a path ending at column c.
dp = matrix[0][:]
for r in range(1, n):
nxt = [0] * n
for c in range(n):
left = dp[c - 1] if c > 0 else float("inf")
right = dp[c + 1] if c + 1 < n else float("inf")
nxt[c] = matrix[r][c] + min(left, dp[c], right)
dp = nxt
return min(dp)
Time complexity: \(O(n^2)\).
Space complexity: \(O(n)\).
Comment on my solution¶
Your solution is correct and achieves optimal \(O(n^2)\) time and \(O(n)\) auxiliary space.
The in-place update works because prev preserves the old left neighbor, while dp[c] and dp[c + 1] have not yet been overwritten. This is efficient but subtler than using a separate nxt row.
The DP comment should say that dp[c] stores the minimum sum from the current row at column c to the bottom, rather than "from this line at row c."
# Ideas:
# - This is a 1D DP because building the minum path from one cell to another
# depends only on adjacent rows.
# - must take care to not overwrite DP states of adjacent row before we need it
class Solution:
def minFallingPathSum(self, matrix: list[list[int]]) -> int:
n = len(matrix)
# dp[c] min sum of from this line at row c to then bottom
dp = matrix[-1][:]
for r in range(n - 2, -1, -1):
for c in range(n):
cur = dp[c]
if c == 0 and c == n - 1:
# one column matrix
dp[c] += matrix[r][c]
elif c == 0:
dp[c] = matrix[r][c] + min(dp[c], dp[c + 1])
elif c == n - 1:
dp[c] = matrix[r][c] + min(prev, dp[c])
else:
dp[c] = matrix[r][c] + min(prev, dp[c], dp[c + 1])
prev = cur
return min(dp)