Maximum Number of Points with Cost

MediumDynamic Programming · Prefix/Suffix Max🧩 Grid DPLeetCode #1937 ↗Updated

Problem

You are given an 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.
Input[[1,2,3],[1,5,1],[3,1,1]]Output9 (3 + 5 + 3 - 1 - 1)
Input[[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

Java
class Solution {
    public long maxPoints(int[][] points) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
The transition 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).
PatternGrid DP

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

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

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

At a glance

LevelApproachTimeSpace
Brute ForceRecursion over Column ChoicesO(nm)O(m)
BetterRow-by-Row DP (All Pairs)O(m · n2)O(n)
OptimalLeft & Right Running MaxO(m · n)O(n)
Common pitfalls
  • Returning int — 105 rows of 105 points overflow; use long.
  • 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.
Interview tips
  • Write the O(m·n2) DP first, then ask how to speed up the inner max.
  • Split |p - c| into the two cases p ≤ c and p ≥ c on the whiteboard.
  • Note the constraint m·n ≤ 105: a single row can be 105 wide.
Pattern
DP with |i - j| transition cost → replace the inner max loop with a forward and a backward running max.
My notes saved in this browser