🧠
Brute Force (Pure Recursion)
💡 Starting with brute force helps understand the problem's recursive structure and why naive recursion is inefficient due to repeated calculations.
Intuition
Try all possible falling paths starting from each element in the first row and recursively compute the minimum sum for each path.
Algorithm
- Start from each element in the first row.
- Recursively explore the three possible adjacent cells in the next row.
- Calculate the sum of the current cell and the minimum of the recursive calls.
- Return the minimum sum among all starting points.
💡 The recursion tree grows exponentially because each cell branches into up to three recursive calls.
Recurrence:f(i,j) = matrix[i][j] + min(f(i+1,j), f(i+1,j-1), f(i+1,j+1))
from math import inf
def minFallingPathSum(matrix):
n = len(matrix)
def dfs(i, j):
if j < 0 or j >= n:
return inf
if i == n - 1:
return matrix[i][j]
return matrix[i][j] + min(dfs(i+1, j), dfs(i+1, j-1), dfs(i+1, j+1))
return min(dfs(0, j) for j in range(n))
# Example usage
if __name__ == '__main__':
matrix = [[2,1,3],[6,5,4],[7,8,9]]
print(minFallingPathSum(matrix)) # Output: 13
Line Notes
def dfs(i, j):Defines recursive helper to compute min path sum from (i,j)
if j < 0 or j >= n:Bounds check to avoid invalid columns
if i == n - 1:Base case: last row returns its own value
return matrix[i][j] + min(dfs(i+1, j), dfs(i+1, j-1), dfs(i+1, j+1))Recursive call exploring all three adjacent next-row cells
public class Solution {
public int minFallingPathSum(int[][] matrix) {
int n = matrix.length;
Integer[][] memo = new Integer[n][n];
int minSum = Integer.MAX_VALUE;
for (int j = 0; j < n; j++) {
minSum = Math.min(minSum, dfs(matrix, 0, j, n, memo));
}
return minSum;
}
private int dfs(int[][] matrix, int i, int j, int n, Integer[][] memo) {
if (j < 0 || j >= n) return Integer.MAX_VALUE;
if (i == n - 1) return matrix[i][j];
if (memo[i][j] != null) return memo[i][j];
int left = dfs(matrix, i + 1, j - 1, n, memo);
int down = dfs(matrix, i + 1, j, n, memo);
int right = dfs(matrix, i + 1, j + 1, n, memo);
memo[i][j] = matrix[i][j] + Math.min(left, Math.min(down, right));
return memo[i][j];
}
public static void main(String[] args) {
Solution sol = new Solution();
int[][] matrix = {{2,1,3},{6,5,4},{7,8,9}};
System.out.println(sol.minFallingPathSum(matrix)); // Output: 13
}
}
Line Notes
if (j < 0 || j >= n) return Integer.MAX_VALUE;Bounds check to avoid invalid columns
if (i == n - 1) return matrix[i][j];Base case returns cell value at last row
memo[i][j] = matrix[i][j] + Math.min(left, Math.min(down, right));Memoize minimum path sum for (i,j)
for (int j = 0; j < n; j++)Try all starting points in first row
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
int dfs(const vector<vector<int>>& matrix, int i, int j, vector<vector<int>>& memo) {
int n = matrix.size();
if (j < 0 || j >= n) return INT_MAX;
if (i == n - 1) return matrix[i][j];
if (memo[i][j] != INT_MIN) return memo[i][j];
int left = dfs(matrix, i + 1, j - 1, memo);
int down = dfs(matrix, i + 1, j, memo);
int right = dfs(matrix, i + 1, j + 1, memo);
memo[i][j] = matrix[i][j] + min({left, down, right});
return memo[i][j];
}
int minFallingPathSum(vector<vector<int>>& matrix) {
int n = matrix.size();
vector<vector<int>> memo(n, vector<int>(n, INT_MIN));
int ans = INT_MAX;
for (int j = 0; j < n; ++j) {
ans = min(ans, dfs(matrix, 0, j, memo));
}
return ans;
}
int main() {
vector<vector<int>> matrix = {{2,1,3},{6,5,4},{7,8,9}};
cout << minFallingPathSum(matrix) << endl; // Output: 13
return 0;
}
Line Notes
if (j < 0 || j >= n) return INT_MAX;Avoid invalid column indices
if (i == n - 1) return matrix[i][j];Base case returns last row cell value
if (memo[i][j] != INT_MIN) return memo[i][j];Return cached result to avoid recomputation
ans = min(ans, dfs(matrix, 0, j, memo));Try all starting points in first row
function minFallingPathSum(matrix) {
const n = matrix.length;
const memo = Array.from({ length: n }, () => Array(n).fill(null));
function dfs(i, j) {
if (j < 0 || j >= n) return Infinity;
if (i === n - 1) return matrix[i][j];
if (memo[i][j] !== null) return memo[i][j];
const left = dfs(i + 1, j - 1);
const down = dfs(i + 1, j);
const right = dfs(i + 1, j + 1);
memo[i][j] = matrix[i][j] + Math.min(left, down, right);
return memo[i][j];
}
let result = Infinity;
for (let j = 0; j < n; j++) {
result = Math.min(result, dfs(0, j));
}
return result;
}
// Example usage
const matrix = [[2,1,3],[6,5,4],[7,8,9]];
console.log(minFallingPathSum(matrix)); // Output: 13
Line Notes
if (j < 0 || j >= n) return Infinity;Bounds check to prevent invalid indices
if (i === n - 1) return matrix[i][j];Base case returns last row value
if (memo[i][j] !== null) return memo[i][j];Memoization to avoid repeated work
for (let j = 0; j < n; j++)Try all possible starting columns in first row
TimeO(3^n) without memoization
SpaceO(n) recursion stack depth
Each cell branches into up to 3 recursive calls, leading to exponential time.
💡 For n=10, this means up to 3^10 = 59049 calls, which is very slow.
Interview Verdict: TLE / Use only to introduce problem structure
This approach is too slow for large inputs but helps understand the problem's recursive nature.