101 Logo
onenoughtone

Solution Approach

Solution Overview

There are 3 main approaches to solve this problem:

  1. Dynamic Programming (4D) - Complex approach
  2. Dynamic Programming (3D) - Complex approach
  3. Dynamic Programming with Memoization - Complex approach

Approach 1: Dynamic Programming (4D)

The key insight for solving this problem is to reframe it. Instead of thinking about one person making a round trip, we can think of it as two people starting from (0, 0) and both reaching (n-1, n-1).

At each step, both people can move either right or down, and we need to maximize the total number of cherries they collect. If both people are at the same cell, we should count the cherry only once.

Let's define dp[r1][c1][r2][c2] as the maximum cherries that can be collected when person 1 is at (r1, c1) and person 2 is at (r2, c2).

The recurrence relation is:

dp[r1][c1][r2][c2] = grid[r1][c1] + grid[r2][c2] - (r1 == r2 && c1 == c2 ? grid[r1][c1] : 0) + max(dp[r1-1][c1][r2-1][c2], dp[r1-1][c1][r2][c2-1], dp[r1][c1-1][r2-1][c2], dp[r1][c1-1][r2][c2-1])

The base case is dp[0][0][0][0] = grid[0][0].

However, there's a key observation we can make: if both people take the same number of steps, then r1 + c1 = r2 + c2. This means we can reduce the 4D DP array to a 3D DP array dp[r1][c1][r2], where c2 = r1 + c1 - r2.

The recurrence relation becomes:

dp[r1][c1][r2] = grid[r1][c1] + (r1 == r2 && c1 == r1 + c1 - r2 ? 0 : grid[r2][r1 + c1 - r2]) + max(dp[r1-1][c1][r2-1], dp[r1-1][c1][r2], dp[r1][c1-1][r2-1], dp[r1][c1-1][r2])

We need to be careful about the boundary conditions and ensure that both people are on valid cells (not thorns).

Algorithm:

  1. Initialize a 4D DP array dp of size (n+1) × (n+1) × (n+1) × (n+1), with all elements set to -Infinity.
  2. Set the base case: dp[0][0][0][0] = grid[0][0].
  3. For each position (r1, c1, r2, c2) where both people are on valid cells:
  4. a. Calculate the cherries collected at this position: cherries = grid[r1][c1] + grid[r2][c2] - (r1 == r2 && c1 == c2 ? grid[r1][c1] : 0).
  5. b. Calculate the maximum cherries from the previous positions: prev = max(dp[r1-1][c1][r2-1][c2], dp[r1-1][c1][r2][c2-1], dp[r1][c1-1][r2-1][c2], dp[r1][c1-1][r2][c2-1]).
  6. c. Update dp[r1][c1][r2][c2] = cherries + prev.
  7. Return max(0, dp[n-1][n-1][n-1][n-1]), as the answer can't be negative.

Time Complexity:

O(n^4)

We need to fill in the DP table of size n^4, and each cell takes constant time to compute.

Space Complexity:

O(n^4)

We use a 4D DP array of size n^4 to store the maximum cherries for each position.

Approach 2: Dynamic Programming (3D)

We can optimize the space complexity of the dynamic programming approach by using a 3D array instead of a 4D array.

The key observation is that if both people take the same number of steps, then r1 + c1 = r2 + c2. This means we can reduce the 4D DP array to a 3D DP array dp[r1][c1][r2], where c2 = r1 + c1 - r2.

Let's define dp[r1][c1][r2] as the maximum cherries that can be collected when person 1 is at (r1, c1) and person 2 is at (r2, r1 + c1 - r2).

The recurrence relation is:

dp[r1][c1][r2] = grid[r1][c1] + (r1 == r2 && c1 == r1 + c1 - r2 ? 0 : grid[r2][r1 + c1 - r2]) + max(dp[r1-1][c1][r2-1], dp[r1-1][c1][r2], dp[r1][c1-1][r2-1], dp[r1][c1-1][r2])

We need to be careful about the boundary conditions and ensure that both people are on valid cells (not thorns).

Algorithm:

  1. Initialize a 3D DP array dp of size n × n × n, with all elements set to -Infinity.
  2. Set the base case: dp[0][0][0] = grid[0][0].
  3. For each position (r1, c1, r2) where both people are on valid cells:
  4. a. Calculate c2 = r1 + c1 - r2.
  5. b. Calculate the cherries collected at this position: cherries = grid[r1][c1] + (r1 == r2 && c1 == c2 ? 0 : grid[r2][c2]).
  6. c. Calculate the maximum cherries from the previous positions: prev = max(dp[r1-1][c1][r2-1], dp[r1-1][c1][r2], dp[r1][c1-1][r2-1], dp[r1][c1-1][r2]).
  7. d. Update dp[r1][c1][r2] = cherries + prev.
  8. Return max(0, dp[n-1][n-1][n-1]), as the answer can't be negative.

Time Complexity:

O(n^3)

We need to fill in the DP table of size n^3, and each cell takes constant time to compute.

Space Complexity:

O(n^3)

We use a 3D DP array of size n^3 to store the maximum cherries for each position.

Approach 3: Dynamic Programming with Memoization

We can also solve this problem using a top-down approach with memoization, which is essentially a recursive solution with caching to avoid redundant calculations.

Let's define a recursive function dp(r1, c1, r2, c2) that returns the maximum cherries that can be collected when person 1 is at (r1, c1) and person 2 is at (r2, c2).

The recurrence relation is the same as in the bottom-up approach:

dp(r1, c1, r2, c2) = grid[r1][c1] + grid[r2][c2] - (r1 == r2 && c1 == c2 ? grid[r1][c1] : 0) + max(dp(r1-1, c1, r2-1, c2), dp(r1-1, c1, r2, c2-1), dp(r1, c1-1, r2-1, c2), dp(r1, c1-1, r2, c2-1))

We can optimize this by using the observation that r1 + c1 = r2 + c2, so we can define dp(r1, c1, r2) where c2 = r1 + c1 - r2.

To avoid redundant calculations, we use memoization to store the results of subproblems that we've already solved.

Algorithm:

  1. Initialize a memoization table memo of size n × n × n, with all elements set to -1.
  2. Define a recursive function dp(r1, c1, r2) that returns the maximum cherries that can be collected when person 1 is at (r1, c1) and person 2 is at (r2, r1 + c1 - r2).
  3. Base cases:
  4. a. If r1 < 0 or c1 < 0 or r2 < 0 or c2 < 0, return -Infinity (invalid position).
  5. b. If grid[r1][c1] == -1 or grid[r2][c2] == -1, return -Infinity (thorn).
  6. c. If r1 == 0 && c1 == 0 && r2 == 0 && c2 == 0, return grid[0][0] (starting position).
  7. If memo[r1][c1][r2] != -1, return memo[r1][c1][r2] (already computed).
  8. Calculate c2 = r1 + c1 - r2.
  9. Calculate the cherries collected at this position: cherries = grid[r1][c1] + (r1 == r2 && c1 == c2 ? 0 : grid[r2][c2]).
  10. Calculate the maximum cherries from the previous positions: prev = max(dp(r1-1, c1, r2-1), dp(r1-1, c1, r2), dp(r1, c1-1, r2-1), dp(r1, c1-1, r2)).
  11. Update memo[r1][c1][r2] = cherries + prev and return it.
  12. Call dp(n-1, n-1, n-1) and return max(0, result), as the answer can't be negative.

Time Complexity:

O(n^3)

We need to compute the result for each state (r1, c1, r2), and there are n^3 possible states. Each state takes constant time to compute.

Space Complexity:

O(n^3)

We use a memoization table of size n^3 to store the results of subproblems, and the recursion stack can go up to a depth of O(n).

Pseudocode

solution.pseudo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function cherryPickup(grid):
n = grid.length
// Initialize DP array
dp = new 4D array of size (n+1) × (n+1) × (n+1) × (n+1), initialized with -Infinity
// Base case
dp[0][0][0][0] = grid[0][0]
// Fill DP array
for r1 from 0 to n-1:
for c1 from 0 to n-1:
for r2 from 0 to n-1:
for c2 from 0 to n-1:
// Skip invalid cells
if grid[r1][c1] == -1 or grid[r2][c2] == -1:
continue
// Calculate cherries collected
cherries = grid[r1][c1]
if r1 != r2 or c1 != c2:
cherries += grid[r2][c2]
// Calculate maximum cherries from previous positions
prev = max(
dp[r1-1][c1][r2-1][c2] if r1 > 0 and r2 > 0 else -Infinity,
dp[r1-1][c1][r2][c2-1] if r1 > 0 and c2 > 0 else -Infinity,
dp[r1][c1-1][r2-1][c2] if c1 > 0 and r2 > 0 else -Infinity,
dp[r1][c1-1][r2][c2-1] if c1 > 0 and c2 > 0 else -Infinity
)
// Update DP array
if prev != -Infinity:
dp[r1][c1][r2][c2] = cherries + prev
return max(0, dp[n-1][n-1][n-1][n-1])
ProblemSolutionCode
101 Logo
onenoughtone