|
| 1 | +# Cherry Pickup |
| 2 | + |
| 3 | +You are given an n x n grid representing a field of cherries, each cell is one of three possible integers. |
| 4 | + |
| 5 | +- 0 means the cell is empty, so you can pass through, |
| 6 | +- 1 means the cell contains a cherry that you can pick up and pass through, or |
| 7 | +- -1 means the cell contains a thorn that blocks your way. |
| 8 | + |
| 9 | +Return the maximum number of cherries you can collect by following the rules below: |
| 10 | + |
| 11 | +- Starting at the position (0, 0) and reaching (n - 1, n - 1) by moving right or down through valid path cells (cells |
| 12 | + with value 0 or 1). |
| 13 | +- After reaching (n - 1, n - 1), returning to (0, 0) by moving left or up through valid path cells. |
| 14 | +- When passing through a path cell containing a cherry, you pick it up, and the cell becomes an empty cell 0. |
| 15 | +- If there is no valid path between (0, 0) and (n - 1, n - 1), then no cherries can be collected. |
| 16 | + |
| 17 | +> Note: A valid path requires traveling from the top-left corner to the bottom-right corner and successfully returning |
| 18 | +> to the starting point. |
| 19 | +
|
| 20 | +## Constraints |
| 21 | + |
| 22 | +- n == `grid.length` |
| 23 | +- n == `grid[i].length` |
| 24 | +- 1 <= `n` <= 50 |
| 25 | +- `grid[i][j]` is -1, 0, or 1. |
| 26 | +- `grid[0][0]` != -1 |
| 27 | +- `grid[n - 1][n - 1]` != -1 |
| 28 | + |
| 29 | +## Examples |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +Example 4 |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | +```text |
| 40 | +Input: grid = [[0,1,-1],[1,0,-1],[1,1,1]] |
| 41 | +Output: 5 |
| 42 | +Explanation: The player started at (0, 0) and went down, down, right right to reach (2, 2). |
| 43 | +4 cherries were picked up during this single trip, and the matrix becomes [[0,1,-1],[0,0,-1],[0,0,0]]. |
| 44 | +Then, the player went left, up, up, left to return home, picking up one more cherry. |
| 45 | +The total number of cherries picked up is 5, and this is the maximum possible. |
| 46 | +``` |
| 47 | + |
| 48 | +Example 5 |
| 49 | + |
| 50 | +```text |
| 51 | +Input: grid = [[1,1,-1],[1,-1,1],[-1,1,1]] |
| 52 | +Output: 0 |
| 53 | +``` |
| 54 | + |
| 55 | +## Topics |
| 56 | + |
| 57 | +- Array |
| 58 | +- Dynamic Programming |
| 59 | +- Matrix |
| 60 | + |
| 61 | +## Solution(s) |
| 62 | + |
| 63 | +1. [Dynamic Programming (Top Down)](#dynamic-programming-top-down) |
| 64 | +2. [Dynamic Programming (Top Down) 2](#dynamic-programming-top-down-2) |
| 65 | +3. [Dynamic Programming (Bottom Up)](#dynamic-programming-bottom-up) |
| 66 | + |
| 67 | +### Dynamic Programming (Top Down) |
| 68 | + |
| 69 | +Instead of walking from end to beginning, let's reverse the second leg of the path, so we are only considering two paths |
| 70 | +from the beginning to the end. |
| 71 | + |
| 72 | +Notice after `t` steps, each position `(r, c)` we could be, is on the line `r + c = t`. So if we have two people at |
| 73 | +positions `(r1, c1)` and `(r2, c2)`, then `r2 = r1 + c1 - c2`. That means the variables `r1`, `c1`, `c2` uniquely |
| 74 | +determine 2 people who have walked the same `r1 + c1` number of steps. This sets us up for dynamic programming quite |
| 75 | +nicely. |
| 76 | + |
| 77 | +Let `dp[r1][c1][c2]` be the most number of cherries obtained by two people starting at `(r1, c1)` and `(r2, c2)` and |
| 78 | +walking towards `(n - 1, n - 1)` picking up cherries, where `r2 = r1 + c1 - c2`. |
| 79 | + |
| 80 | +If `grid[r1][c1]` and `grid[r2][c2]` are not thorns, then the value of `dp[r1][c1][c2]` is (`grid[r1][c1]` + `grid[r2][c2]`), |
| 81 | +plus the maximum of `dp[r1 + 1][c1][c2]`, `dp[r1][c1 + 1][c2]`, `dp[r1 + 1][c1][c2 + 1]`, `dp[r1][c1 + 1][c2 + 1]` as |
| 82 | +appropriate. We should also be careful to not double count in case `(r1, c1) == (r2, c2)`. |
| 83 | + |
| 84 | +Why did we say it was the maximum of `dp[r + 1][c1][c2]` etc.? It corresponds to the 4 possibilities for persons 1 and |
| 85 | +2 moving down and right: |
| 86 | + |
| 87 | +- Person 1 down and person 2 down: `dp[r1 + 1][c1][c2]`; |
| 88 | +- Person 1 right and person 2 down: `dp[r1][c1 + 1][c2]`; |
| 89 | +- Person 1 down and person 2 right: `dp[r1 + 1][c1][c2 + 1]`; |
| 90 | +- Person 1 right and person 2 right: `dp[r1][c1 + 1][c2 + 1]`; |
| 91 | + |
| 92 | +#### Complexity |
| 93 | + |
| 94 | +- **Time Complexity**: `O(n^3)`, where `n` is the length of grid. Our dynamic programming has `n^3` states, and each |
| 95 | + state is calculated once. |
| 96 | +- **Space Complexity**: `O(n^3)`, the size of memo. |
| 97 | + |
| 98 | + |
| 99 | + |
| 100 | +### Dynamic Programming (Top Down) 2 |
| 101 | + |
| 102 | +The naive approach might be to find the optimal path from (0, 0) to (n-1, n-1), collect cherries along the way, then |
| 103 | +find the optimal return path on the modified grid. However, this greedy approach fails because the first path might block |
| 104 | +better options for the return journey. |
| 105 | + |
| 106 | +The key insight is recognizing that going from (0, 0) to (n-1, n-1) and back is equivalent to having two people start |
| 107 | +simultaneously from (0, 0) and both reach (n-1, n-1). Why? Because any path from start to end and back can be split into |
| 108 | +two paths from start to end - one person follows the original forward path, and another follows the return path in |
| 109 | +reverse. |
| 110 | + |
| 111 | +Since both people move simultaneously, after k steps, if person 1 is at (i1, j1) and person 2 is at (i2, j2), we know |
| 112 | +that i1 + j1 = k and i2 + j2 = k. This means we only need to track the row positions i1 and i2, as the column positions |
| 113 | +can be derived: j1 = k - i1 and j2 = k - i2. |
| 114 | + |
| 115 | +This transforms our problem into a 3-dimensional DP: `f[k][i1][i2]` represents the maximum cherries collected when both |
| 116 | +people have taken k steps, with person 1 at row i1 and person 2 at row i2. |
| 117 | + |
| 118 | +At each step, both people can move either right or down (equivalent to coming from left or up in the previous step). This |
| 119 | +gives us four possible combinations of previous positions to consider. When both people land on the same cell, we count |
| 120 | +that cherry only once. |
| 121 | + |
| 122 | +The total number of steps to reach (n-1, n-1) from (0, 0) is 2n-2 (we need to move n-1 steps right and n-1 steps down). |
| 123 | +The final answer is the maximum cherries collected when both people reach (n-1, n-1) after 2n-2 steps. |
| 124 | + |
| 125 | +#### Algorithm |
| 126 | + |
| 127 | +The implementation uses dynamic programming with three dimensions. Let's walk through the key components: |
| 128 | + |
| 129 | +1. **State Definition**: |
| 130 | + - `f[k][i1][i2]` represents the maximum cherries collected when both persons have taken k steps total |
| 131 | + - Person 1 is at position (i1, k-i1) |
| 132 | + - Person 2 is at position (i2, k-i2) |
| 133 | + |
| 134 | +2. **Initialization** |
| 135 | + - Create a 3D array with dimensions (2n-1) × n × n |
| 136 | + - Initialize all values to negative infinity (-inf) to represent invalid states |
| 137 | + - Set `f[0][0][0]` = `grid[0][0]` as both persons start at (0, 0) |
| 138 | + |
| 139 | +3. **State Transition**: For each step `k` from 1 to `2n-2` |
| 140 | + - Iterate through all possible positions (i1, j1) for person 1 where j1 = k - i1 |
| 141 | + - Iterate through all possible positions (i2, j2) for person 2 where j2 = k - i2 |
| 142 | + - Check validity |
| 143 | + - Both j1 and j2 must be within bounds [0, n) |
| 144 | + - Neither `grid[i1][j1]` nor `grid[i2][j2]` should be -1 (thorn) |
| 145 | + - Calculate cherries collected at current positions: |
| 146 | + - If both persons are at the same cell (i1 == i2), count cherry once: t = `grid[i1][j1]` |
| 147 | + - If at different cells, sum both: t = `grid[i1][j1]` + `grid[i2][j2]` |
| 148 | + - Consider all valid previous positions: |
| 149 | + - Person 1 could have come from (i1-1, j1) or (i1, j1-1), meaning x1 ∈ {i1-1, i1} |
| 150 | + - Person 2 could have come from (i2-1, j2) or (i2, j2-1), meaning x2 ∈ {i2-1, i2} |
| 151 | + - Update: `f[k][i1][i2] = max(f[k][i1][i2], f[k-1][x1][x2] + t)` |
| 152 | + |
| 153 | +4. **Final Answer** |
| 154 | + - The maximum cherries when both reach (n-1, n-1) is `f[2n-2][n-1][n-1]` |
| 155 | + - Return `max(0, f[2n-2][n-1][n-1])` to handle cases where no valid path exists (result would be negative infinity) |
| 156 | + |
| 157 | +#### Complexity |
| 158 | + |
| 159 | +- **Time Complexity: O(n^3)** |
| 160 | + The algorithm uses dynamic programming with three nested loops: |
| 161 | + - The outermost loop iterates through `k` from `1` to `2n - 2`, which is `O(n)` iterations |
| 162 | + - The second loop iterates through `i1` from `0` to `n - 1`, which is `O(n)` iterations |
| 163 | + - The third loop iterates through `i2` from `0` to `n - 1`, which is `O(n)` iterations |
| 164 | + - Inside these three loops, there are two more nested loops for `x1` and `x2`, but these only iterate through at most |
| 165 | + 2 values each (from i - 1 to i), making them `O(1)` |
| 166 | + |
| 167 | + Therefore, the overall time complexity is `O(n) × O(n) × O(n) × O(1) = O(n^3)`. |
| 168 | + |
| 169 | +- **Space Complexity: O(n^3)** |
| 170 | + The algorithm creates a 3D DP array `f` with dimensions: |
| 171 | + - First dimension: `(2n - 1)` elements, which is `O(n)` |
| 172 | + - Second dimension: `n` elements, which is `O(n)` |
| 173 | + - Third dimension: `n` elements, which is `O(n)` |
| 174 | + |
| 175 | + The total space used by the DP array is `O(n) × O(n) × O(n) = O(n^3)`. Where `n` is the side length of the grid. |
| 176 | + |
| 177 | + |
| 178 | +### Dynamic Programming (Bottom Up) |
| 179 | + |
| 180 | +Like in [the first approach](#dynamic-programming-top-down), we have the idea of dynamic programming. |
| 181 | + |
| 182 | +Say `r1 + c1 = t` is the t-th layer. Since our recursion only references the next layer, we only need to keep two layers |
| 183 | +in memory at a time. |
| 184 | + |
| 185 | +At time `t`, let `dp[c1][c2]` be the most cherries that we can pick up for two people going from `(0, 0)` to `(r1, c1)` |
| 186 | +and `(0, 0)` to `(r2, c2)`, where `r1 = t-c1`, `r2 = t-c2`. Our dynamic program proceeds similarly to [the first approach](#dynamic-programming-top-down). |
| 187 | + |
| 188 | +#### Complexity Analysis |
| 189 | + |
| 190 | +- **Time Complexity**: `O(n^3`), where n is the length of grid. We have three for-loops of size n. |
| 191 | +- **Space Complexity**: `O(n^2)`, the sizes of `dp` and `dp2`. |
0 commit comments