546. Remove Boxes
Problem Description
You are given several boxes with different colors represented by different positive numbers.
You may experience several rounds to remove boxes until there is no box left. Each time you can choose some continuous boxes with the same color (i.e., composed of k boxes, k >= 1), remove them and get k * k points.
Return the maximum points you can get.
Example 1:
Input: boxes = [1,3,2,2,2,3,4,3,1]
Output: 23
Explanation:
[1,3,2,2,2,3,4,3,1] --> [1,3,3,4,3,1] (3*3=9 points)
[1,3,3,4,3,1] --> [1,3,3,3,1] (1*1=1 points)
[1,3,3,3,1] --> [1,1] (3*3=9 points)
[1,1] --> [] (2*2=4 points)
Total points = 9 + 1 + 9 + 4 = 23
Example 2:
Input: boxes = [1,1,1]
Output: 9
Example 3:
Input: boxes = [1]
Output: 1
Constraints:
1 <= boxes.length <= 1001 <= boxes[i] <= 100
Solution
Python Solution
class Solution:
def removeBoxes(self, boxes: List[int]) -> int:
@cache
def dp(l: int, r: int, k: int) -> int:
if l > r:
return 0
# Skip repeated boxes to optimize
while l + 1 <= r and boxes[l] == boxes[l + 1]:
l += 1
k += 1
# Remove current group of boxes
result = (k + 1) * (k + 1) + dp(l + 1, r, 0)
# Try to merge non-adjacent same colored boxes
for i in range(l + 1, r + 1):
if boxes[i] == boxes[l]:
result = max(result, dp(l + 1, i - 1, 0) + dp(i, r, k + 1))
return result
return dp(0, len(boxes) - 1, 0)
Time Complexity: O(n⁴)
Where n is the length of boxes. We have three dimensions in our DP and an inner loop.
Space Complexity: O(n³)
For the memoization cache storing states of (l, r, k).
Java Solution
class Solution {
private int[][][] memo;
private int[] boxes;
public int removeBoxes(int[] boxes) {
int n = boxes.length;
this.boxes = boxes;
this.memo = new int[n][n][n];
return dp(0, n - 1, 0);
}
private int dp(int l, int r, int k) {
if (l > r) return 0;
if (memo[l][r][k] > 0) return memo[l][r][k];
// Skip repeated boxes
int origL = l, origK = k;
while (l + 1 <= r && boxes[l] == boxes[l + 1]) {
l++;
k++;
}
// Remove current group
int result = (k + 1) * (k + 1) + dp(l + 1, r, 0);
// Try merging non-adjacent boxes
for (int i = l + 1; i <= r; i++) {
if (boxes[i] == boxes[l]) {
result = Math.max(result, dp(l + 1, i - 1, 0) + dp(i, r, k + 1));
}
}
memo[origL][r][origK] = result;
return result;
}
}
Time Complexity: O(n⁴)
Where n is the length of boxes. We have three dimensions in our DP and an inner loop.
Space Complexity: O(n³)
For the memoization array storing states of (l, r, k).
C++ Solution
class Solution {
private:
vector>> memo;
vector boxes;
int dp(int l, int r, int k) {
if (l > r) return 0;
if (memo[l][r][k] > 0) return memo[l][r][k];
// Skip repeated boxes
int origL = l, origK = k;
while (l + 1 <= r && boxes[l] == boxes[l + 1]) {
l++;
k++;
}
// Remove current group
int result = (k + 1) * (k + 1) + dp(l + 1, r, 0);
// Try merging non-adjacent boxes
for (int i = l + 1; i <= r; i++) {
if (boxes[i] == boxes[l]) {
result = max(result, dp(l + 1, i - 1, 0) + dp(i, r, k + 1));
}
}
return memo[origL][r][origK] = result;
}
public:
int removeBoxes(vector& boxes) {
int n = boxes.size();
this.boxes = boxes;
memo = vector>>(n, vector>(n, vector(n)));
return dp(0, n - 1, 0);
}
};
Time Complexity: O(n⁴)
Where n is the length of boxes. We have three dimensions in our DP and an inner loop.
Space Complexity: O(n³)
For the memoization vector storing states of (l, r, k).
JavaScript Solution
/**
* @param {number[]} boxes
* @return {number}
*/
var removeBoxes = function(boxes) {
const n = boxes.length;
const memo = Array(n).fill().map(() =>
Array(n).fill().map(() => Array(n).fill(0)));
const dp = (l, r, k) => {
if (l > r) return 0;
if (memo[l][r][k] > 0) return memo[l][r][k];
// Skip repeated boxes
let origL = l, origK = k;
while (l + 1 <= r && boxes[l] === boxes[l + 1]) {
l++;
k++;
}
// Remove current group
let result = (k + 1) * (k + 1) + dp(l + 1, r, 0);
// Try merging non-adjacent boxes
for (let i = l + 1; i <= r; i++) {
if (boxes[i] === boxes[l]) {
result = Math.max(result, dp(l + 1, i - 1, 0) + dp(i, r, k + 1));
}
}
memo[origL][r][origK] = result;
return result;
};
return dp(0, n - 1, 0);
};
Time Complexity: O(n⁴)
Where n is the length of boxes. We have three dimensions in our DP and an inner loop.
Space Complexity: O(n³)
For the memoization array storing states of (l, r, k).
C# Solution
public class Solution {
private int[][][] memo;
private int[] boxes;
public int RemoveBoxes(int[] boxes) {
int n = boxes.Length;
this.boxes = boxes;
memo = new int[n][][];
for (int i = 0; i < n; i++) {
memo[i] = new int[n][];
for (int j = 0; j < n; j++) {
memo[i][j] = new int[n];
}
}
return DP(0, n - 1, 0);
}
private int DP(int l, int r, int k) {
if (l > r) return 0;
if (memo[l][r][k] > 0) return memo[l][r][k];
// Skip repeated boxes
int origL = l, origK = k;
while (l + 1 <= r && boxes[l] == boxes[l + 1]) {
l++;
k++;
}
// Remove current group
int result = (k + 1) * (k + 1) + DP(l + 1, r, 0);
// Try merging non-adjacent boxes
for (int i = l + 1; i <= r; i++) {
if (boxes[i] == boxes[l]) {
result = Math.Max(result, DP(l + 1, i - 1, 0) + DP(i, r, k + 1));
}
}
memo[origL][r][origK] = result;
return result;
}
}
Time Complexity: O(n⁴)
Where n is the length of boxes. We have three dimensions in our DP and an inner loop.
Space Complexity: O(n³)
For the memoization array storing states of (l, r, k).
Approach Explanation
The solution uses dynamic programming with memoization:
- Key Insights:
- State representation
- Optimal substructure
- Memoization
- Box merging
- Algorithm Steps:
- Define states
- Handle base cases
- Try all splits
- Maximize points
Implementation Details:
- 3D memoization
- State transitions
- Optimization tricks
- Recursive solution
Optimization Insights:
- Skip repeated boxes
- Cache results
- Early pruning
- State reduction
Edge Cases:
- Single box
- All same color
- Alternating colors
- Empty array