题目:
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:
23Explanation:
[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.
思路:
个人感觉这道题目确实算是DP和DFS里面很难的一道了,自己看了网上的代码才完全搞清楚。下面代码的基本思路还是DP,但是它不是通过简单的循环来完成自底向上的计算,而是通过记忆化的DFS来实现的:
我们定义dp[l][r][k]表示在[l, r]区间并且在后面包含了k个与boxes[r]相同颜色的boxes的情况下,可以获得的最大得分,显然题目要求的就是dp[0][boxes.size() - 1][0]。在实现的过程中,我们采用DFS + memorization来进行状态转移,即如果需要计算一个子问题,我们首先查看原来是不是已经计算过了,如果是,则直接拿来用;否则才用DFS进行计算。那么怎么计算呢?
首先将dp[l][r][k]的值初始化为dp[l][r - 1][0] + (k + 1)^2,表示首先消除l到r-1之间的boxes,然后将boxes[r]连同后面的k个boxes一起消除。
然后就尝试对dp[l][r][k]进行更新了:如果在l到r-1区间内有boxes[i]和boxes[r]相同的字符,那么可以尝试首先将区间[i + 1, r - 1]消除,这样i就和后面的k + 1个boxes连起来了,其可以获得分数就是需要进一步计算的dp[l][i][k + 1]。
代码:
class Solution {
public:
int removeBoxes(vector& boxes) {
return DFS(boxes, 0, boxes.size() - 1, 0);
}
private:
int DFS(vector& boxes, int l,int r,int k) {
if (l > r) {
return 0;
}
if (dp[l][r][k]) {
return dp[l][r][k]; // if we have calculated this DFS result, return it
}
dp[l][r][k] = DFS(boxes, l, r - 1, 0) + (k + 1) * (k + 1); // box[l][r] result is box[l][r-1]+(k+1)^2
for (int i = l; i < r; ++i) { // go through each box from left
if (boxes[i] == boxes[r]) { // check for same color box as boxes[r]
// if we found same color box, then we have a chance to get a higher value by group
// boxes[l] ~ boxes[i] and boxes[r] together, plus the value from boxes[i+1] ~ boxes[r-1]
dp[l][r][k] = max(dp[l][r][k], DFS(boxes, l, i, k + 1) + DFS(boxes, i + 1, r - 1, 0));
}
}
return dp[l][r][k];
}
int dp[100][100][100]; // initialized to 0, dp[left][right][k] means value from boxes[left]~boxes[right] followed by
// k same color boxes. Follow does not mean strictly consecutive boxes, for example,
// [1, 3, 2, 3, 4], 3 can be followed by the other 3 because we can remove 2 first.
};