Given an n x n
array of integers matrix
, return the minimum sum of any falling path through matrix
.
A falling path starts at any element in the first row and chooses the element in the next row that is either directly below or diagonally left/right. Specifically, the next element from position (row, col)
will be (row + 1, col - 1)
, (row + 1, col)
, or (row + 1, col + 1)
.
For example:
Consider the following matrix:
[[2, 1, 3],
[6, 5, 4],
[7, 8, 9]]
There are two falling paths with a minimum sum of 13.
As another example, consider:
[[-19, 57],
[-40, -5]]
The falling path with the minimum sum is -59.
Write a function to efficiently compute the minimum falling path sum for a given square matrix of integers. What is the time and space complexity of your solution? How does your solution handle edge cases, such as empty matrices or matrices with a single element?
# Minimum Falling Path Sum
## Problem Description
Given an `n x n` array of integers `matrix`, the goal is to find the minimum sum of any falling path through the `matrix`. A falling path starts at any element in the first row and chooses the element in the next row that is either directly below or diagonally left/right. In other words, from position `(row, col)`, the next element will be `(row + 1, col - 1)`, `(row + 1, col)`, or `(row + 1, col + 1)`.
For example:
matrix = [[2,1,3],[6,5,4],[7,8,9]]
The minimum falling path sum is 13 (1 -> 5 -> 7 or 1 -> 5 -> 8).
## Brute Force Solution
A brute-force approach would involve exploring every possible falling path and computing their sums. We can use recursion to achieve this. Start from each cell in the first row and recursively explore the possible paths downwards. The minimum sum among all paths is the result.
```python
def min_falling_path_sum_brute_force(matrix):
n = len(matrix)
def find_path(row, col):
if row == n:
return 0
if col < 0 or col >= n:
return float('inf')
return matrix[row][col] + min(
find_path(row + 1, col - 1),
find_path(row + 1, col),
find_path(row + 1, col + 1)
)
min_sum = float('inf')
for start_col in range(n):
min_sum = min(min_sum, find_path(0, start_col))
return min_sum
We can use dynamic programming to optimize this process. We will build a DP table of the same size as the input matrix, where dp[i][j]
stores the minimum falling path sum ending at matrix[i][j]
. The transitions are as follows:
dp[i][j] = matrix[i][j] + min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1])
Handle boundary conditions carefully. The minimum falling path sum will be the minimum value in the last row of the DP table.
def min_falling_path_sum_dp(matrix):
n = len(matrix)
dp = [[0] * n for _ in range(n)]
# Initialize the first row of DP table with the first row of the matrix
for j in range(n):
dp[0][j] = matrix[0][j]
# Fill the DP table
for i in range(1, n):
for j in range(n):
# Calculate the minimum path sum from the previous row
if j == 0:
dp[i][j] = matrix[i][j] + min(dp[i-1][j], dp[i-1][j+1])
elif j == n - 1:
dp[i][j] = matrix[i][j] + min(dp[i-1][j-1], dp[i-1][j])
else:
dp[i][j] = matrix[i][j] + min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1])
# The result is the minimum value in the last row
return min(dp[n-1])
n x n
matrix once.n x n
to store intermediate results.n >= 0
instead of n >= 1
, we would need to account for this.def min_falling_path_sum_dp_optimized_space(matrix):
n = len(matrix)
if n == 0:
return 0
if n == 1:
return matrix[0][0]
dp = [row[:] for row in matrix] # Using the original matrix for DP
for i in range(1, n):
for j in range(n):
if j == 0:
dp[i][j] += min(dp[i-1][j], dp[i-1][j+1])
elif j == n - 1:
dp[i][j] += min(dp[i-1][j-1], dp[i-1][j])
else:
dp[i][j] += min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1])
return min(dp[n-1])