Talentd
FleetCode
Make and follow sheets.Sign in

Minimum Falling Path Sum solution and explanation

MediumArrayDynamic ProgrammingMatrix5 min read60.8% acceptanceUpdated 9 Apr 2026
Minimum Falling Path Sum | Recursion | Memo | Bottom Up | Leetcode 931codestorywithMIK · 48:56 · 18K viewsWatch on YouTube
9 more videos on this problem
  1. Minimum Falling Path Sum | Recursion | Memo | Bottom Up | Leetcode 931codestorywithMIK · 48:56 · 18K views
  2. Minimum Falling Path Sum - Leetcode 931 - PythonNeetCodeIO · 14:02 · 17K views
  3. Leetcode 931 - Dynamic Programming | Min Falling Path SumNideesh Terapalli · 6:17 · 7K views
  4. Minimum Falling Path Sum | Leetcode 931 | HindiCodebix · 15:31 · 5K views
  5. 931. Minimum Falling Path Sum | LEETCODE MEDIUM | DYNAMIC PROGRAMMINGcode Explainer · 9:05 · 4K views
  6. 931. Minimum Falling Path Sum | Recursion - DP - DP OptimisedAryan Mittal · 14:49 · 2K views
  7. [Java] Leetcode 931. Minimum Falling Path Sum [DP Min/Max Path to Target #6]Eric Programming · 12:09 · 2K views
  8. Leetcode 931 Minimum Falling Path Sum | Coding Decoded SDE SheetCoding Decoded · 6:14 · 793 views
  9. 931. Minimum Falling Path Sum | JavaScript | Iteration | Simple | Easy Solution | MemoizationLeetCodeWithMonu · 17:00 · 439 views
  10. 12. Minimum Falling Path Sum | LeetCode Medium 931| Dynamic ProgrammingAceCoder Academy · 16:59 · 286 views

The problem

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).

Example 1:

Input: matrix = [[2,1,3],[6,5,4],[7,8,9]]
Output: 13
Explanation: There are two falling paths with a minimum sum as shown.

Example 2:

Input: matrix = [[-19,57],[-40,-5]]
Output: -59
Explanation: The falling path with a minimum sum is shown.

Constraints:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 100
  • -100 <= matrix[i][j] <= 100

Approach overview

Problem Overview: You are given an n x n matrix of integers. A falling path starts at any cell in the first row and moves to the next row either directly below, diagonally left, or diagonally right. The goal is to compute the minimum possible sum of values along any valid falling path from the top row to the bottom row.

Approach 1: Top-Down Dynamic Programming with Memoization (Time: O(n^2), Space: O(n^2))

This approach models the problem as recursion over rows. For each cell (r, c), recursively compute the minimum path sum starting from that cell by exploring the three valid next positions: (r+1, c-1), (r+1, c), and (r+1, c+1). Many subproblems repeat, so store results in a memo table to avoid recomputation. Each cell is solved once, which reduces exponential recursion to quadratic time. This method is intuitive if you think in terms of exploring all paths but caching results.

The recursion stops when the last row is reached. Out-of-bound column moves are ignored. Because every matrix cell is computed once and stored, the complexity becomes O(n^2). This pattern is common in dynamic programming problems on grids.

Approach 2: Bottom-Up Dynamic Programming (Time: O(n^2), Space: O(n^2) or O(1) in-place)

The bottom-up strategy processes the matrix row by row. Starting from the second row, update each cell by adding the minimum of the three reachable cells from the previous row: up-left, up, and up-right. This converts the matrix into a DP table where each entry represents the minimum path sum reaching that cell.

For cell (r, c), compute matrix[r][c] += min(prev[c], prev[c-1], prev[c+1]) while handling boundary columns carefully. After processing all rows, the answer is the minimum value in the last row. This method iterates once over the grid and avoids recursion overhead. Because the DP values can overwrite the original matrix, the extra space can be reduced to O(1).

This technique is typical for problems involving transitions in a matrix or grid where each state depends on nearby cells. Iterating through the array structure row by row keeps the implementation simple and efficient.

Recommended for interviews: Bottom-up dynamic programming is the expected solution. It demonstrates that you can convert recursive state transitions into iterative DP and optimize space if needed. Showing the top-down memoized version first can help explain the recurrence, but the bottom-up implementation signals stronger DP problem-solving skills.

Approach 1: Bottom-Up Dynamic Programming Approach

Using a dynamic programming matrix, you can start from the second-last row of the matrix and calculate the minimum path sum by traversing through possible paths (directly below, diagonally left, and diagonally right). Update the matrix in-place to use constant space.

class Solution:
    def minFallingPathSum(self, matrix):
        n = len(matrix)
        for i in range(n-2, -1, -1):
            for j in range(n):
                best = matrix[i+1][j]
                if j > 0:
                    best = min(best, matrix[i+1][j-1])
                if j < n-1:
                    best = min(best, matrix[i+1][j+1])
                matrix[i][j] += best
        return min(matrix[0])
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 best = matrix[i + 1][j];
                if (j > 0) best = Math.min(best, matrix[i + 1][j - 1]);
                if (j < n - 1) best = Math.min(best, matrix[i + 1][j + 1]);
                matrix[i][j] += best;
            }
        }
        int minSum = Integer.MAX_VALUE;
        for (int val : matrix[0]) {
            minSum = Math.min(minSum, val);
        }
        return minSum;
    }
}
#include <vector>
#include <algorithm>
using namespace std;

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 mn = matrix[i + 1][j];
            if (j > 0) mn = min(mn, matrix[i + 1][j - 1]);
            if (j < n - 1) mn = min(mn, matrix[i + 1][j + 1]);
            matrix[i][j] += mn;
        }
    }
    return *min_element(matrix[0].begin(), matrix[0].end());
}
var minFallingPathSum = function(matrix) {
    const n = matrix.length;
    for (let i = n - 2; i >= 0; i--) {
        for (let j = 0; j < n; j++) {
            let best = matrix[i + 1][j];
            if (j > 0) best = Math.min(best, matrix[i + 1][j - 1]);
            if (j < n - 1) best = Math.min(best, matrix[i + 1][j + 1]);
            matrix[i][j] += best;
        }
    }
    return Math.min(...matrix[0]);
};
#include <stdio.h>
#include <limits.h>

int minFallingPathSum(int** matrix, int matrixSize, int* matrixColSize) {
    for (int row = matrixSize - 2; row >= 0; row--) {
        for (int col = 0; col < matrixColSize[row]; col++) {
            int best = matrix[row + 1][col];
            if (col > 0) {
                best = (best < matrix[row + 1][col - 1]) ? best : matrix[row + 1][col - 1];
            }
            if (col < matrixColSize[row + 1] - 1) {
                best = (best < matrix[row + 1][col + 1]) ? best : matrix[row + 1][col + 1];
            }
            matrix[row][col] += best;
        }
    }
    int minSum = INT_MAX;
    for (int i = 0; i < matrixColSize[0]; i++) {
        if(matrix[0][i] < minSum) {
            minSum = matrix[0][i];
        }
    }
    return minSum;
}
public 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 best = matrix[i + 1][j];
                if (j > 0) best = Math.Min(best, matrix[i + 1][j - 1]);
                if (j < n - 1) best = Math.Min(best, matrix[i + 1][j + 1]);
                matrix[i][j] += best;
            }
        }
        int minSum = int.MaxValue;
        foreach (int val in matrix[0]) {
            minSum = Math.Min(minSum, val);
        }
        return minSum;
    }
}

This Python solution modifies the matrix in place to track minimal paths as it calculates from the bottom to the top row.

Complexity

Time Complexity: O(n^2)
Space Complexity: O(1)

Try this approach in the editor

Approach 2: Top-Down Dynamic Programming with Memoization

For this approach, we use recursion with memoization to explore paths starting from the first row to the last row. We store intermediate results to avoid redundant calculations.

class Solution:
    def minFallingPathSum(self, matrix):
        n = len(matrix)
        memo = [[float('inf')] * n for _ in range(n)]
    
        def dfs(row, col):
            if row == n:
                return 0
            if memo[row][col] != float('inf'):
                return memo[row][col]
            res = matrix[row][col] + dfs(row + 1, col)
            if col > 0:
                res = min(res, matrix[row][col] + dfs(row + 1, col - 1))
            if col < n - 1:
                res = min(res, matrix[row][col] + dfs(row + 1, col + 1))
            memo[row][col] = res
            return res

        minSum = float('inf')
        for col in range(n):
            minSum = min(minSum, dfs(0, col))
        return minSum
import java.util.Arrays;

class Solution {
    private int[][] memo;
    private int dfs(int[][] matrix, int row, int col) {
        int n = matrix.length;
        if (row == n) return 0;
        if (memo[row][col] != Integer.MAX_VALUE) return memo[row][col];
        int res = matrix[row][col] + dfs(matrix, row + 1, col);
        if (col > 0) res = Math.min(res, matrix[row][col] + dfs(matrix, row + 1, col - 1));
        if (col < n - 1) res = Math.min(res, matrix[row][col] + dfs(matrix, row + 1, col + 1));
        return memo[row][col] = res;
    }

    public int minFallingPathSum(int[][] matrix) {
        int n = matrix.length;
        memo = new int[n][n];
        for (int[] row : memo) {
            Arrays.fill(row, Integer.MAX_VALUE);
        }
        int minSum = Integer.MAX_VALUE;
        for (int col = 0; col < n; col++) {
            minSum = Math.min(minSum, dfs(matrix, 0, col));
        }
        return minSum;
    }
}
#include <vector>
#include <algorithm>
using namespace std;

vector<vector<int>> memo;

int dfs(vector<vector<int>>& matrix, int row, int col) {
    int n = matrix.size();
    if (row == n) return 0;
    if (memo[row][col] != INT_MAX) return memo[row][col];
    int res = matrix[row][col] + dfs(matrix, row + 1, col);
    if (col > 0) res = min(res, matrix[row][col] + dfs(matrix, row + 1, col - 1));
    if (col < n - 1) res = min(res, matrix[row][col] + dfs(matrix, row + 1, col + 1));
    return memo[row][col] = res;
}

int minFallingPathSum(vector<vector<int>>& matrix) {
    int n = matrix.size();
    memo.assign(n, vector<int>(n, INT_MAX));
    int minSum = INT_MAX;
    for (int col = 0; col < n; ++col) {
        minSum = min(minSum, dfs(matrix, 0, col));
    }
    return minSum;
}
var minFallingPathSum = function(matrix) {
    const n = matrix.length;
    const memo = Array.from({ length: n }, () => Array(n).fill(Infinity));

    const dfs = (row, col) => {
        if (row === n) return 0;
        if (memo[row][col] !== Infinity) return memo[row][col];
        let minSum = matrix[row][col] + dfs(row + 1, col);
        if (col > 0) minSum = Math.min(minSum, matrix[row][col] + dfs(row + 1, col - 1));
        if (col < n - 1) minSum = Math.min(minSum, matrix[row][col] + dfs(row + 1, col + 1));
        memo[row][col] = minSum;
        return minSum;
    };

    let minPathSum = Infinity;
    for (let col = 0; col < n; col++) {
        minPathSum = Math.min(minPathSum, dfs(0, col));
    }
    return minPathSum;
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int min(int a, int b) { return (a < b) ? a : b; }

int dfs(int** matrix, int row, int col, int n, int** memo) {
    if (row == n) return 0; 
    if (memo[row][col] != INT_MAX) return memo[row][col];
    int res = INT_MAX;
    res = min(res, matrix[row][col] + dfs(matrix, row + 1, col, n, memo));
    if (col > 0) res = min(res, matrix[row][col] + dfs(matrix, row + 1, col - 1, n, memo));
    if (col < n - 1) res = min(res, matrix[row][col] + dfs(matrix, row + 1, col + 1, n, memo));
    memo[row][col] = res;
    return res;
}

int minFallingPathSum(int** matrix, int matrixSize, int* matrixColSize) {
    int** memo = (int**)malloc(sizeof(int*) * matrixSize);
    for (int i = 0; i < matrixSize; i++) {
        memo[i] = (int*)malloc(sizeof(int) * (*matrixColSize));
        for (int j = 0; j < *matrixColSize; j++) {
            memo[i][j] = INT_MAX;
        }
    }
    int minSum = INT_MAX;
    for (int col = 0; col < *matrixColSize; col++) {
        minSum = min(minSum, dfs(matrix, 0, col, matrixSize, memo));
    }
    for (int i = 0; i < matrixSize; i++) free(memo[i]);
    free(memo);
    return minSum;
}
public class Solution {
    private int[][] memo;

    public int MinFallingPathSum(int[][] matrix) {
        int n = matrix.Length;
        memo = new int[n][];
        for (int i = 0; i < n; i++) {
            memo[i] = new int[n];
            for (int j = 0; j < n; j++) {
                memo[i][j] = int.MaxValue;
            }
        }
        int minSum = int.MaxValue;
        for (int col = 0; col < n; col++) {
            minSum = Math.Min(minSum, Dfs(matrix, 0, col));
        }
        return minSum;
    }

    private int Dfs(int[][] matrix, int row, int col) {
        int n = matrix.Length;
        if (row == n) return 0;
        if (memo[row][col] != int.MaxValue) return memo[row][col];
        int res = matrix[row][col] + Dfs(matrix, row + 1, col);
        if (col > 0) res = Math.Min(res, matrix[row][col] + Dfs(matrix, row + 1, col - 1));
        if (col < n - 1) res = Math.Min(res, matrix[row][col] + Dfs(matrix, row + 1, col + 1));
        memo[row][col] = res;
        return res;
    }
}

In Python, the solution employs memoization with a recursive DFS function that avoids repeating work by storing the results of subproblems.

Complexity

Time Complexity: O(n^2)
Space Complexity: O(n^2)

Try this approach in the editor

Approach 3: Default Approach

function minFallingPathSum(matrix: number[][]): number {
    const n = matrix.length;
    const f: number[] = new Array(n).fill(0);
    for (const row of matrix) {
        const g = f.slice();
        for (let j = 0; j < n; ++j) {
            if (j > 0) {
                g[j] = Math.min(g[j], f[j - 1]);
            }
            if (j + 1 < n) {
                g[j] = Math.min(g[j], f[j + 1]);
            }
            g[j] += row[j];
        }
        f.splice(0, n, ...g);
    }
    return Math.min(...f);
}
func minFallingPathSum(matrix [][]int) int {
	n := len(matrix)
	f := make([]int, n)
	for _, row := range matrix {
		g := make([]int, n)
		copy(g, f)
		for j, x := range row {
			if j > 0 {
				g[j] = min(g[j], f[j-1])
			}
			if j+1 < n {
				g[j] = min(g[j], f[j+1])
			}
			g[j] += x
		}
		f = g
	}
	return slices.Min(f)
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Bottom-Up Dynamic Programming Approach

Time Complexity: O(n^2)
Space Complexity: O(1)

Top-Down Dynamic Programming with Memoization

Time Complexity: O(n^2)
Space Complexity: O(n^2)

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Top-Down DP with MemoizationO(n^2)O(n^2)When deriving the recurrence relation or explaining the problem using recursion
Bottom-Up Dynamic ProgrammingO(n^2)O(n^2) or O(1) in-placePreferred for production or interviews due to iterative structure and possible space optimization

Frequently asked questions

Is Minimum Falling Path Sum easy or hard?

Minimum Falling Path Sum is considered a medium-level problem. The challenge comes from recognizing the dynamic programming transition and handling edge columns correctly when checking diagonal neighbors.

How to solve Minimum Falling Path Sum in O(n)?

The standard solution cannot be reduced to O(n) time because every cell in the n x n matrix must be evaluated. The optimal complexity is O(n^2). However, space usage can be reduced to O(1) extra space by updating the matrix directly during the DP computation.

What is the best approach for Minimum Falling Path Sum?

The best approach is bottom-up dynamic programming. Iterate row by row and update each cell with the minimum value from the three reachable cells in the previous row. This processes the entire matrix once with O(n^2) time complexity and can be optimized to O(1) extra space by modifying the matrix in-place.

What data structure is used in Minimum Falling Path Sum?

The main data structure is a 2D matrix combined with a dynamic programming table. The DP state represents the minimum sum needed to reach each cell. Transitions use adjacent cells from the previous row.

What is the time complexity of Minimum Falling Path Sum?

The optimal dynamic programming solution runs in O(n^2) time because each of the n x n matrix cells is processed exactly once. Each computation checks at most three neighboring cells from the previous row, which is constant work.

Minimum Falling Path Sum Python or Java solution approach

Both Python and Java implementations typically use bottom-up dynamic programming. Iterate through the matrix starting from the second row and update each cell using the minimum of the three possible parent cells. The final answer is the minimum element in the last row.

Is Minimum Falling Path Sum asked at Google, Amazon, or Meta?

Minimum Falling Path Sum represents a classic grid dynamic programming pattern. Variants of this problem frequently appear in interviews at companies like Amazon, Google, and Meta where candidates must compute optimal paths in a matrix using DP transitions.

Comments

Now write it yourselfClose this page and solve Minimum Falling Path Sum in the editor, without looking.
Practise Minimum Falling Path Sum