Cherry Pickup

Solve this Problem
Hard25–30 min
Topics
Companies
Practice:LeetCode ↗
Given a square grid where each cell is blocked, empty, or holds one cherry, imagine making two trips from the top-left corner to the bottom-right corner, each only moving right or down. Find the maximum total number of cherries collectible across both trips combined — a cell visited by both trips only counts once — or 0 if no such pair of trips is possible at all. Since both trips always take the same number of steps to have moved the same distance, their positions at any point can be tracked by row alone (the column follows from the step count), which keeps the state small enough to work with directly: track, after each step, the best total collectible so far for every pair of rows the two trips could be on. Starting both trips together at the top-left corner and sweeping forward one step at a time — where each trip independently either moves down or moves right — lets every later step be resolved using totals already computed for the step before it, skipping any pair of positions that would land on a blocked cell. Once both trips reach the bottom-right corner, that entry holds the answer.

Test Case 1:

Input:grid = [[1,1,1],[1,-1,1],[1,1,1]]
Output:8
Explanation:Two trips from the top-left to the bottom-right corner, each only moving right or down, collect a combined 8 cherries while routing around the blocked center cell — a shared cell counts once.

Test Case 2:

Input:grid = [[1,0],[0,1]]
Output:2
Explanation:With only one possible pair of routes, both trips collect the corner cells: 1 + 1 = 2.

Test Case 3:

Input:grid = [[1]]
Output:1
Explanation:A single cell is both the start and the end — it's collected once, not twice.

Constraints

  • 1 ≤ grid.length ≤ 15 (a square n×n grid)
  • grid[i][j] is -1 (blocked), 0 (empty), or 1 (one cherry)
  • grid[0][0] and grid[n-1][n-1] are never -1
🚀

Try the Dry Run

Don't just read the solution — watch it execute, one step at a time.

Approach & Solutions

Brute Force — Recursive Without Memoization

Brute

Think of it as two trips made at the same time, both starting at the top-left corner and both only moving right or down, each step taken simultaneously so both trips are always the same number of steps in. At every step, each trip independently moves right or down, giving up to four combined moves, and a move into a blocked cell — or off the grid — simply isn't allowed. Whenever both trips are on the same cell, its cherry is only collected once. From any pair of positions, the most cherries collectible from there onward is this step's cherries (for one or both trips) plus whichever of the reachable next pairs of positions collects the most; once both trips reach the bottom-right corner, there's nothing left to collect but that cell itself. Trying every combination of moves finds the maximum, though the same pair of positions ends up recomputed whenever different routes funnel into it, and the whole result is floored at 0 in case no route through survives at all.

TimeO(4^n)
SpaceO(n)
1class Solution { 2 private int[][] grid; 3 private int n; 4 5 public int cherryPickup(int[][] grid) { 6 this.grid = grid; 7 this.n = grid.length; 8 int result = solve(0, 0, 0); 9 return Math.max(result, 0); 10 } 11 12 private int solve(int r1, int c1, int r2) { 13 int c2 = r1 + c1 - r2; 14 if (r1 >= n || c1 >= n || r2 >= n || c2 >= n || grid[r1][c1] == -1 || grid[r2][c2] == -1) { 15 return Integer.MIN_VALUE; 16 } 17 if (r1 == n - 1 && c1 == n - 1) { 18 return grid[r1][c1]; 19 } 20 int best = Integer.MIN_VALUE; 21 best = Math.max(best, solve(r1 + 1, c1, r2 + 1)); 22 best = Math.max(best, solve(r1 + 1, c1, r2)); 23 best = Math.max(best, solve(r1, c1 + 1, r2 + 1)); 24 best = Math.max(best, solve(r1, c1 + 1, r2)); 25 if (best == Integer.MIN_VALUE) return Integer.MIN_VALUE; 26 int cherries = grid[r1][c1]; 27 if (r1 != r2) cherries += grid[r2][c2]; 28 return cherries + best; 29 } 30}

Optimal — Bottom-Up 2D Table Per Step

Optimal

Since both trips always take the same number of steps to reach any given pair of rows, a trip's column is fixed once its row and the step count are known (column = step − row). That means the state only needs each trip's row, so track a table indexed by "trip 1's row" and "trip 2's row" holding the most cherries collectible so far after a given number of steps. Step 0 starts both trips together at the top-left corner. At every step after that, each new entry is this step's cherries (for the pair of cells, counted once if they coincide) plus the best entry reachable from the previous step across the up to four combined moves — each trip either stayed in the same row (moved right) or advanced a row (moved down) — skipping any move into a blocked cell or off the grid. After the final step, when both trips have reached the bottom-right corner, that entry holds the answer, floored at 0.

TimeO(n³)
SpaceO(n²)
1class Solution { 2 public int cherryPickup(int[][] grid) { 3 int n = grid.length; 4 int[][] dp = new int[n][n]; 5 for (int[] row : dp) Arrays.fill(row, Integer.MIN_VALUE); 6 if (grid[0][0] != -1) dp[0][0] = grid[0][0]; 7 for (int s = 1; s <= 2 * n - 2; s++) { 8 int[][] ndp = new int[n][n]; 9 for (int[] row : ndp) Arrays.fill(row, Integer.MIN_VALUE); 10 for (int r1 = 0; r1 < n; r1++) { 11 int c1 = s - r1; 12 if (c1 < 0 || c1 >= n || grid[r1][c1] == -1) continue; 13 for (int r2 = 0; r2 < n; r2++) { 14 int c2 = s - r2; 15 if (c2 < 0 || c2 >= n || grid[r2][c2] == -1) continue; 16 int best = Integer.MIN_VALUE; 17 for (int d1 = 0; d1 <= 1; d1++) { 18 for (int d2 = 0; d2 <= 1; d2++) { 19 int pr1 = r1 - d1, pr2 = r2 - d2; 20 if (pr1 < 0 || pr2 < 0) continue; 21 best = Math.max(best, dp[pr1][pr2]); 22 } 23 } 24 if (best == Integer.MIN_VALUE) continue; 25 int cherries = grid[r1][c1]; 26 if (r1 != r2) cherries += grid[r2][c2]; 27 ndp[r1][r2] = cherries + best; 28 } 29 } 30 dp = ndp; 31 } 32 return Math.max(dp[n - 1][n - 1], 0); 33 } 34}

Related Problems