<p>Given an <code>n x n</code> integer matrix <code>grid</code>, return <em>the minimum sum of a <strong>falling path with non-zero shifts</strong></em>.</p>

<p>A <strong>falling path with non-zero shifts</strong> is a choice of exactly one element from each row of <code>grid</code> such that no two elements chosen in adjacent rows are in the same column.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/08/10/falling-grid.jpg" style="width: 244px; height: 245px;" />
<pre>
<strong>Input:</strong> grid = [[1,2,3],[4,5,6],[7,8,9]]
<strong>Output:</strong> 13
<strong>Explanation:</strong> 
The possible falling paths are:
[1,5,9], [1,5,7], [1,6,7], [1,6,8],
[2,4,8], [2,4,9], [2,6,7], [2,6,8],
[3,4,8], [3,4,9], [3,5,7], [3,5,9]
The falling path with the smallest sum is&nbsp;[1,5,7], so the answer is&nbsp;13.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> grid = [[7]]
<strong>Output:</strong> 7
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>n == grid.length == grid[i].length</code></li>
	<li><code>1 &lt;= n &lt;= 200</code></li>
	<li><code>-99 &lt;= grid[i][j] &lt;= 99</code></li>
</ul>

#include <ranges>
namespace rn = std::ranges;
namespace vw = std::views;

class Solution {
public:
    int minFallingPathSum(std::vector<std::vector<int>>& grid) {
        constexpr int MAX_VAL = 101 * 201;
        const int N = grid.size();

        // Keep track of the minimum value for each element, by using
        // the recurrence relation:
        //  min_sum(i, j) = min{for all k != j}(min_sum(i - 1, k))
        //
        // Do it in-place to reduce space complexity

        for (int i = 1; i < N; ++i) {
            // Compute the smallest AND second smallest values
            // of the previous row to reduce time complexity by
            // an order of N.
            //
            // We can use these because we'll use the smallest
            // value for all j except the j = {idx of smallest},
            // for which we'll use the second smallest.

            int smallest_min = MAX_VAL;
            int smallest_min_idx = 0;
            int alt_min = MAX_VAL;

            for (int min_j = 0; min_j < N; ++min_j) {
                int val = grid[i - 1][min_j];
                if (val < smallest_min) {
                    alt_min = std::exchange(smallest_min, val);
                    smallest_min_idx = min_j;
                } else {
                    alt_min = std::min(alt_min, val);
                }
            }

            for (int j = 0; j < N; ++j) {
                if (j == smallest_min_idx) {
                    grid[i][j] += alt_min;
                } else {
                    grid[i][j] += smallest_min;
                }
            }
        }

        return std::ranges::min(grid.back());
    }
};
17200