<p>You are given an <code>m x n</code> integer matrix <code>points</code> (<strong>0-indexed</strong>). Starting with <code>0</code> points, you want to <strong>maximize</strong> the number of points you can get from the matrix.</p>

<p>To gain points, you must pick one cell in <strong>each row</strong>. Picking the cell at coordinates <code>(r, c)</code> will <strong>add</strong> <code>points[r][c]</code> to your score.</p>

<p>However, you will lose points if you pick a cell too far from the cell that you picked in the previous row. For every two adjacent rows <code>r</code> and <code>r + 1</code> (where <code>0 &lt;= r &lt; m - 1</code>), picking cells at coordinates <code>(r, c<sub>1</sub>)</code> and <code>(r + 1, c<sub>2</sub>)</code> will <strong>subtract</strong> <code>abs(c<sub>1</sub> - c<sub>2</sub>)</code> from your score.</p>

<p>Return <em>the <strong>maximum</strong> number of points you can achieve</em>.</p>

<p><code>abs(x)</code> is defined as:</p>

<ul>
	<li><code>x</code> for <code>x &gt;= 0</code>.</li>
	<li><code>-x</code> for <code>x &lt; 0</code>.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong><strong> </strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/07/12/screenshot-2021-07-12-at-13-40-26-diagram-drawio-diagrams-net.png" style="width: 300px; height: 300px;" />
<pre>
<strong>Input:</strong> points = [[1,2,3],[1,5,1],[3,1,1]]
<strong>Output:</strong> 9
<strong>Explanation:</strong>
The blue cells denote the optimal cells to pick, which have coordinates (0, 2), (1, 1), and (2, 0).
You add 3 + 5 + 3 = 11 to your score.
However, you must subtract abs(2 - 1) + abs(1 - 0) = 2 from your score.
Your final score is 11 - 2 = 9.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/07/12/screenshot-2021-07-12-at-13-42-14-diagram-drawio-diagrams-net.png" style="width: 200px; height: 299px;" />
<pre>
<strong>Input:</strong> points = [[1,5],[2,3],[4,2]]
<strong>Output:</strong> 11
<strong>Explanation:</strong>
The blue cells denote the optimal cells to pick, which have coordinates (0, 1), (1, 1), and (2, 0).
You add 5 + 3 + 4 = 12 to your score.
However, you must subtract abs(1 - 1) + abs(1 - 0) = 1 from your score.
Your final score is 12 - 1 = 11.
</pre>

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

<ul>
	<li><code>m == points.length</code></li>
	<li><code>n == points[r].length</code></li>
	<li><code>1 &lt;= m, n &lt;= 10<sup>5</sup></code></li>
	<li><code>1 &lt;= m * n &lt;= 10<sup>5</sup></code></li>
	<li><code>0 &lt;= points[r][c] &lt;= 10<sup>5</sup></code></li>
</ul>

# My initial solution was working in O(n^3) with this loop:

# for row in range(1, m):
#             binaryRow = row % 2
#             for col in range(n):
#                 for col2 in range(n):
#                     dp[binaryRow][col] = max(dp[binaryRow][col], points[row][col] + dp[1^binaryRow][col2] - (abs(col - col2)))

# Then I read the discussion, solved #104 problem and understood how to optimize it to O(n^2).
# Formula for computing score from point [r-1][i] to [r][j] is dp[r-1][i] + points[r][j] - abs(i - j), where abs(i - j) is the distance between columns.

# We need to rewrite this formula into 2 formulas, left-to-right and right-to-left:

# In left-to-right pass, current column j will always be greater or equal to i, so we need to add i and subtract j, to achieve negative distance.
# Left-to-right: score = (dp[r-1][i] + i) + (points[r][j] - j). Second part of the equation is always known, so we need to maximize the first part.

# In right-to-left pass, i will always be greater or equal to current column j, so we need to subtract i and add j, to achieve negative distance.
# Right-to-left: score = (dp[r-1][i] - i) + (points[r][j] + j). Second part of the equation is also known, so we maximize the first part.

class Solution:
    def maxPoints(self, points: List[List[int]]) -> int:
        m, n = len(points), len(points[0])
        dp = [[-1] * n for _ in range(2)] # we only need previous row, so I will only use 2 rows in dp to store prev and cur rows

        for col in range(n):
            dp[0][col] = points[0][col]

        for row in range(1, m):
            binaryRow = row % 2

            maxValue = dp[1^binaryRow][0] + 0 # dp[r-1][i] + i
            for col in range(n):
                maxValue = max(maxValue, dp[1^binaryRow][col] + col)
                dp[binaryRow][col] = max(dp[binaryRow][col], maxValue + points[row][col] - col)

            maxValue = dp[1^binaryRow][n-1] - n + 1 # dp[r-1][i] - i
            for col in range(n-1, -1, -1):
                maxValue = max(maxValue, dp[1^binaryRow][col] - col)
                dp[binaryRow][col] = max(dp[binaryRow][col], maxValue + points[row][col] + col)

        finalRow = 1 ^ m % 2
        return max(dp[finalRow][c] for c in range(n))
1685