Problem Statement
leetcode problem link
Memoization [Accepted]
class Solution:
def minFallingPathSum(self, matrix: List[List[int]]) -> int:
N = len(matrix)
@cache
def dp(r, c):
if r == N:
return 0
if not 0 <= c < N:
return float('inf')
val = matrix[r][c]
ans = float('inf')
ans = min(ans, dp(r + 1, c - 1) + val)
ans = min(ans, dp(r + 1, c) + val)
ans = min(ans, dp(r + 1, c + 1) + val)
return ans
res = float('inf')
for col in range(N):
res = min(res, dp(0, col))
return res
Editorial
Approach 1: Brute Force Using Depth First Search
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
int minFallingSum = INT_MAX;
for (int startCol = 0; startCol < matrix.size(); startCol++) {
minFallingSum =
min(minFallingSum, findMinFallingPathSum(matrix, 0, startCol));
}
return minFallingSum;
}
int findMinFallingPathSum(vector<vector<int>>& matrix, int row, int col) {
// check if we are out of the left or right boundary of the matrix
if (col < 0 || col == matrix.size()) {
return INT_MAX;
}
// check if we have reached the last row
if (row == matrix.size() - 1) {
return matrix[row][col];
}
// calculate the minimum falling path sum starting from each possible
// next step
int left = findMinFallingPathSum(matrix, row + 1, col);
int middle = findMinFallingPathSum(matrix, row + 1, col + 1);
int right = findMinFallingPathSum(matrix, row + 1, col - 1);
return min(left, min(middle, right)) + matrix[row][col];
}
};
Approach 2: Top Down Dynamic Programming
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
int minFallingSum = INT_MAX;
vector<vector<optional<int>>> memo(
matrix.size(), vector<optional<int>>(matrix.size(), nullopt));
// start a DFS (with memoization) from each cell in the top row
for (int startCol = 0; startCol < matrix.size(); startCol++) {
minFallingSum = min(minFallingSum, findMinFallingPathSum(
matrix, 0, startCol, memo));
}
return minFallingSum;
}
int findMinFallingPathSum(vector<vector<int>>& matrix, int row, int col,
vector<vector<optional<int>>>& memo) {
// base cases
if (col < 0 || col == matrix.size()) {
return INT_MAX;
}
// check if we have reached the last row
if (row == matrix.size() - 1) {
return matrix[row][col];
}
// check if the results are calculated before
if (memo[row][col] != nullopt) {
return (memo[row][col]).value_or(0);
}
// calculate the minimum falling path sum starting from each possible
// next step
int left = findMinFallingPathSum(matrix, row + 1, col - 1, memo);
int middle = findMinFallingPathSum(matrix, row + 1, col, memo);
int right = findMinFallingPathSum(matrix, row + 1, col + 1, memo);
int minSum = min(left, min(middle, right)) + matrix[row][col];
memo[row][col] = minSum;
return minSum;
}
};
Approach 3: Bottom-Up Dynamic Programming (Tabulation)
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
vector<vector<int>> dp(matrix.size() + 1,
vector<int>(matrix.size() + 1, 0));
for (int row = matrix.size() - 1; row >= 0; row--) {
for (int col = 0; col < matrix.size(); col++) {
if (col == 0) {
dp[row][col] = min(dp[row + 1][col], dp[row + 1][col + 1]) +
matrix[row][col];
} else if (col == matrix.size() - 1) {
dp[row][col] = min(dp[row + 1][col], dp[row + 1][col - 1]) +
matrix[row][col];
} else {
dp[row][col] =
min(dp[row + 1][col],
min(dp[row + 1][col + 1], dp[row + 1][col - 1])) +
matrix[row][col];
}
}
}
int minFallingSum = INT_MAX;
for (int startCol = 0; startCol < matrix.size(); startCol++) {
minFallingSum = min(minFallingSum, dp[0][startCol]);
}
return minFallingSum;
}
};