Cherry Pickup

HardDynamic Programming · Grid DP · Two Walkers🧩 Grid DPLeetCode #741 ↗Updated

Problem

An n x n field has cells that are empty (0), hold a cherry (1) or are blocked by a thorn (-1). Walk from the top-left to the bottom-right moving only right/down, then walk back moving only left/up, never entering thorns. A cherry is picked the first time its cell is visited. Return the most cherries you can collect, or 0 if the corner is unreachable.
Input[[0,1,-1],[1,0,-1],[1,1,1]]Output5
Input[[1,1,-1],[1,-1,1],[-1,1,1]]Output0 (no path to the corner)

1 ≤ n ≤ 50  ·  grid[i][j] ∈ {-1, 0, 1}  ·  start and end cells are never thorns

Try it yourself

Java
class Solution {
    public int cherryPickup(int[][] grid) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
The return trip is just a second forward path, so send two walkers forward at the same time. After t steps both satisfy r + c = t, so the state is (t, r1, r2), and a shared cell is detected simply by r1 == r2.
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 ForceTwo Walkers, Plain Recursion

Time O(42n)Space O(n)

Move both walkers one step at a time (4 combinations of down/right). Both are always on the same anti-diagonal, so c2 = r1 + c1 - r2. Collect the cherries under them, counting a shared cell once, and take the best continuation.

Java
private static final int NEG = Integer.MIN_VALUE / 2;   // "impossible"

public int cherryPickup(int[][] grid) {
    return Math.max(0, walk(grid, 0, 0, 0));
}

// Walker 1 at (r1, c1), walker 2 at (r2, r1 + c1 - r2); both move toward the corner
private int walk(int[][] grid, int r1, int c1, int r2) {
    int n = grid.length, c2 = r1 + c1 - r2;
    if (r1 >= n || c1 >= n || r2 >= n || c2 >= n) return NEG;
    if (grid[r1][c1] == -1 || grid[r2][c2] == -1) return NEG;
    int here = grid[r1][c1] + (r1 != r2 ? grid[r2][c2] : 0);   // same cell counts once
    if (r1 == n - 1 && c1 == n - 1) return here;
    int best = Math.max(
            Math.max(walk(grid, r1 + 1, c1, r2 + 1), walk(grid, r1 + 1, c1, r2)),
            Math.max(walk(grid, r1, c1 + 1, r2 + 1), walk(grid, r1, c1 + 1, r2)));
    return best == NEG ? NEG : here + best;
}

Correct modelling of the problem, but tries every pair of paths.

At a glance

LevelApproachTimeSpace
Brute ForceTwo Walkers, Plain RecursionO(42n)O(n)
BetterMemoized Two-Walker DPO(n3)O(n3)
OptimalBottom-Up by Step, Rolling 2-D TableO(n3)O(n2)
Common pitfalls
  • Two greedy passes (best path, clear it, best path again) — can miss the optimum.
  • Counting a cherry twice when both walkers stand on the same cell.
  • Returning a negative sentinel when the corner is unreachable — the answer must be 0.
Interview tips
  • Show a counter-example to the two-greedy-passes idea before proposing the DP.
  • Explain why reversing the return trip turns it into a second forward walk.
  • Derive the state reduction: c = t - r drops one dimension from (r1,c1,r2,c2).
Pattern
Two simultaneous paths on a grid → walk both in lockstep, index by step and rows, de-duplicate shared cells.
My notes saved in this browser