Maximum Number of Points with Cost
Problem
m x n matrix points of non-negative scores.
Pick exactly one cell in every row and add up their values. However, for each pair of
consecutive rows, if you picked column c1 above and c2 below,
you lose |c1 - c2| points. Return the maximum total you can end with.[[1,2,3],[1,5,1],[3,1,1]]Output9 (3 + 5 + 3 - 1 - 1)[[1,5],[2,3],[4,2]]Output11 (5 + 3 + 4 - 0 - 1)1 ≤ m, n ≤ 105 · m · n ≤ 105 · 0 ≤ points[r][c] ≤ 105 · totals can exceed int ⇒ return long
Try it yourself
class Solution {
public long maxPoints(int[][] points) {
}
}
maxp(prev[p] - |p - c|) splits into two
halves: p ≤ c and p ≥ c. A left-to-right sweep (decaying
by 1 per step) and a right-to-left sweep compute both halves for every column in O(n).Instinct Grid moves that never loop back (right/down, row to row) plus "count or optimise the paths" - build dp[r][c] from the cells that can step in.
Memory hack Every cell asks its parents - a cell's answer comes only from the neighbours that can move into it, so fill cells in the order they arrive.
Open the Grid DP guide →Approaches
Brute ForceRecursion over Column Choices
O(nm)Space O(m)Choose a column in the current row, then recursively try every column in the next row, paying the distance penalty. Every combination of one column per row is examined, which is the definition of the answer.
public long maxPoints(int[][] points) { long best = Long.MIN_VALUE; for (int c = 0; c < points[0].length; c++) best = Math.max(best, bestFrom(points, 0, c)); return best; } // Best total for rows r..m-1 given that column c is picked in row r private long bestFrom(int[][] points, int r, int c) { long here = points[r][c]; if (r == points.length - 1) return here; long bestNext = Long.MIN_VALUE; for (int next = 0; next < points[0].length; next++) { bestNext = Math.max(bestNext, bestFrom(points, r + 1, next) - Math.abs(c - next)); } return here + bestNext; }
Obviously correct, but explodes as soon as there are a few rows.
BetterRow-by-Row DP (All Pairs)
O(m · n2)Space O(n)The best total ending at (r, c) only depends on the best totals of
row r-1. Keep prev[] and, for each column, scan every previous
column to find max(prev[p] - |p - c|).
public long maxPoints(int[][] points) { int m = points.length, n = points[0].length; long[] prev = new long[n]; for (int c = 0; c < n; c++) prev[c] = points[0][c]; for (int r = 1; r < m; r++) { long[] cur = new long[n]; for (int c = 0; c < n; c++) { long best = Long.MIN_VALUE; for (int p = 0; p < n; p++) best = Math.max(best, prev[p] - Math.abs(p - c)); cur[c] = best + points[r][c]; } prev = cur; } long ans = Long.MIN_VALUE; for (long v : prev) ans = Math.max(ans, v); return ans; }
Removes the exponential blow-up, but n2 per row is too slow for one wide row.
OptimalLeft & Right Running Max
O(m · n)Space O(n)left[c] = max(left[c-1] - 1, prev[c]) is the best
prev[p] - (c - p) over p ≤ c: moving one column further
costs exactly one more point. right[c] is the mirror image, and the
transition is points[r][c] + max(left[c], right[c]).
public long maxPoints(int[][] points) { int m = points.length, n = points[0].length; long[] prev = new long[n]; for (int c = 0; c < n; c++) prev[c] = points[0][c]; long[] left = new long[n], right = new long[n]; for (int r = 1; r < m; r++) { left[0] = prev[0]; for (int c = 1; c < n; c++) left[c] = Math.max(left[c - 1] - 1, prev[c]); right[n - 1] = prev[n - 1]; for (int c = n - 2; c >= 0; c--) right[c] = Math.max(right[c + 1] - 1, prev[c]); long[] cur = new long[n]; for (int c = 0; c < n; c++) cur[c] = points[r][c] + Math.max(left[c], right[c]); prev = cur; } long ans = Long.MIN_VALUE; for (long v : prev) ans = Math.max(ans, v); return ans; }
Dry run[[1,2,3],[1,5,1],[3,1,1]]
- row 0123prev = first row
- left123carry best from left, -1
- right123carry best from right, -1
- row 127*4[1,5,1] + max(left,right)
- max l/r6767 decays by 1 each side
- row 29*873 + 6 = 9 ✔
Linear in the matrix size — handles both very tall and very wide inputs.
-1 per step.”At a glance
| Level | Approach | Time | Space |
|---|---|---|---|
| Brute Force | Recursion over Column Choices | O(nm) | O(m) |
| Better | Row-by-Row DP (All Pairs) | O(m · n2) | O(n) |
| Optimal | Left & Right Running Max | O(m · n) | O(n) |
- Returning
int— 105 rows of 105 points overflow; uselong. - Taking only the left sweep — the best previous column can be to the right.
- Picking the row maximum greedily — the penalty can make a smaller nearby cell better.
- Write the O(m·n2) DP first, then ask how to speed up the inner
max. - Split
|p - c|into the two casesp ≤ candp ≥ con the whiteboard. - Note the constraint
m·n ≤ 105: a single row can be 105 wide.