Description:
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 (composed of k boxes, k >= 1), remove them and get k*k points.
Find the maximum points you can get.
Example 1:
Input:
[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, 3, 1] (1*1=1 points)
----> [1, 1] (3*3=9 points)
----> [] (2*2=4 points)
Note: The number of boxes n would not exceed 100.
问题描述:
有很多颜色不同的箱子,颜色通过不同的数字表示。
你可以经历多个回合去掉所有的箱子。每个回合你可以选择去掉连续的颜色相同的箱子,而这会给你k(去掉的箱子数) * k 分。返回你能得到的最大分
例子:
输入:[1, 3, 2, 2, 2, 3, 4, 3, 1]
输出:23
解释:
首先将3个2去掉,得到9分,然后去掉4,得到1分,然后去掉3个3,得到9分,最后去掉2个1,得到4分,总计23分
解法1(dfs + memorization):
/*
如果对这一题感兴趣,可以看看下面这个链接:
https://leetcode.com/problems/remove-boxes/discuss/101310/Java-top-down-and-bottom-up-DP-solutions
这篇文章不仅讲了解法,还讲了关于这一类特殊dp(普通的子问题定义无法解决)的共性及如何解决
需要注意:
1.问题定义不是,dp[left][right][k],k代表left左边与boxes[left]相等的字符数
2.递归的过程中分了2中情况:
1.直接删除boxes[left]
2.先保留boxes[left],在left和right间找出mid,满足boxes[mid] = boxes[left]
于是递归式变为:dfs(left + 1,mid - 1, 0) + dfs(mid, right, k + 1),需要注意
由于要考虑boxes[left] = boxes[mid],因此第二项里的k变为k + 1
*/
class Solution {
public int removeBoxes(int[] boxes) {
int len = boxes.length;
//注意这里,三维,多出的纬度是k
int[][][] dp = new int[len][len][len];
return dfs(boxes, 0, len - 1, 0, dp);
}
public int dfs(int[] boxes, int i, int j, int k, int[][][] dp){
if(i > j) return 0;
if(dp[i][j][k] != 0) return dp[i][j][k];
for(;i + 1 <= j && boxes[i + 1] == boxes[i];i++,k++);
int res = (k + 1) * (k + 1) + dfs(boxes, i + 1, j, 0, dp);
for(int m = i + 1;m <= j;m++){
if(boxes[m] == boxes[i]){
res = Math.max(res, dfs(boxes, i + 1, m - 1, 0, dp) + dfs(boxes, m, j, k + 1, dp));
}
}
dp[i][j][k] = res;
return res;
}
}
解法2(动态规划):
/*
还是建议看下这篇文章:
https://leetcode.com/problems/remove-boxes/discuss/101310/Java-top-down-and-bottom-up-DP-solutions
其实可以发现,dp中关于k的部分比起递归冗余了不少
*/
class Solution {
public int removeBoxes(int[] boxes) {
int n = boxes.length;
int[][][] dp = new int[n][n][n];
for (int j = 0; j < n; j++) {
for (int k = 0; k <= j; k++) {
dp[j][j][k] = (k + 1) * (k + 1);
}
}
for (int l = 1; l < n; l++) {
for (int j = l; j < n; j++) {
int i = j - l;
for (int k = 0; k <= i; k++) {
int res = (k + 1) * (k + 1) + dp[i + 1][j][0];
for (int m = i + 1; m <= j; m++) {
if (boxes[m] == boxes[i]) {
res = Math.max(res, dp[i + 1][m - 1][0] + dp[m][j][k + 1]);
}
}
dp[i][j][k] = res;
}
}
}
return (n == 0 ? 0 : dp[0][n - 1][0]);
}
}