# 931. Minimum Falling Path Sum



## DFS + memo

T: O(3^row)

S: O(row\*col)

```java
public class Solution {
    public int minFallingPathSum(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;        
        Integer[][] memo = new Integer[m][n];
        
        int min = Integer.MAX_VALUE;
        // 從 row 0 開始跑所有 row 0 的 cell, 來做之後的分支
        // 所以把 0,0  0,1  0,2 丟入 dfs function
        for (int c = 0; c < n; c++) { // row 0, put all (row, col)
            // 因為有做 memo, 所以 0,1  0,2 跑的時候, 其實下面 dfs 的分支都計算過了
            min = Math.min(min, dfs(matrix, 0, c, memo));
        }
        return min;
    }
    // dfs function 來 recursive 計算 min path value
    private int dfs(int[][] matrix, int row, int col, Integer[][] memo) {
        int m = matrix.length;
        int n = matrix[0].length;
        if (!isValid(m, n, row, col)) {
            return 0;
        }
        if (memo[row][col] != null) {
            return memo[row][col];
        }

        int min = Integer.MAX_VALUE;
        
        for (int i = -1; i <= 1; i++) {
            if (!isValid(m, n, row, col+i)) { // why check row..., not row+1 ?
                // because row+1 check is in the beginning of dfs? so why need check?
                continue;
            }
            // for every cell (row, col) 
            // => has 3 branch => (row+1, col-1),(row+1, col), (row+1, col-1)
            // sum = 目前值 + 3 分支的值
            int sum = matrix[row][col] + dfs(matrix, row+1, col + i, memo);
            min = Math.min(min, sum); // 取最小的
            
        }
        memo[row][col] = min; // 紀錄最小值
        return min;
    }
    private boolean isValid(int m, int n, int row, int col) {
        return row >= 0 && row < m && col >=0 && col < n;
    }
}

/*

row.  [0,0  0,1  0,2]  
      /|\
r+1,c-1 c c+1 


T: O(3^row)
S: O(mn)

*/
```



## DP

top down, because this Q ask from top to end's min path sum

```
T: O(mn)
S: O(mn)
```

```java
class Solution {
    public int minFallingPathSum(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        
        int[][] dp = new int[m][n];
        for (int j = 0; j < n; j++) {
            dp[0][j] = matrix[0][j];
        }
        for (int i = 1; i < m; i++) {
            for (int j = 0; j < n; j++) {
                
                dp[i][j] = dp[i-1][j];
                if (j-1 >= 0) {
                    dp[i][j] = Math.min(dp[i][j], dp[i-1][j-1]);
                }
                if (j+1 < n) {
                    dp[i][j] = Math.min(dp[i][j], dp[i-1][j+1]);
                }
                dp[i][j] += matrix[i][j];
            }
        }
        int res = Integer.MAX_VALUE;
        for (int j = 0; j < n; j++) {
            res = Math.min(res, dp[m-1][j]);
        }
        return res;
    }
}

/*
so from questions:

dp[i][j]: the minimum sum of any falling path through matrix, from 0 to m-1 rows.

dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1]) + A[i][j]

at last row find the min(dp[m-1][j]), is the ans

T: O(mn)
S: O(mn)
*/
```
