给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色。
你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止。每一轮你可以移除具有相同颜色的连续 k 个盒子(k >= 1),这样一轮之后你将得到 k*k 个积分。
当你将所有盒子都去掉之后,求你能获得的最大积分和。
示例:
输入:boxes = [1,3,2,2,2,3,4,3,1]
输出:23
解释:
[1, 3, 2, 2, 2, 3, 4, 3, 1]
----> [1, 3, 3, 4, 3, 1] (3*3=9 分)
----> [1, 3, 3, 3, 1] (1*1=1 分)
----> [1, 1] (3*3=9 分)
----> [] (2*2=4 分)
提示:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-boxes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
多说一点:
这个动态规划的思想和下面的dfs的思想不同,dfs是遍历所有的情况得到最终结果的最大值,而动态规划是寻找能和当前区间以及和右端点连成一片的元素一起删除。
class Solution {
public:
int dp[100][100][100];
int removeBoxes(vector<int>& boxes) {
memset(dp, 0, sizeof dp);
return fun(boxes, 0, boxes.size() - 1, 0);
}
int fun(vector<int>& boxes, int l, int r, int k){
if(l > r)
return 0;
if(dp[l][r][k])
return dp[l][r][k];
while(l < r && boxes[r] == boxes[r - 1]){//当右端点左面的元素和右端点相等时,尽可能的将右端点左移,使得相同元素的长度最长
--r;
++k;
}
dp[l][r][k] = fun(boxes, l, r - 1, 0) + (k + 1) * (k + 1);
//右端点左面和右端点相等组成连续序列的情况
for(int i = l; i < r; ++i){
if(boxes[i] == boxes[r]){
dp[l][r][k] = max(dp[l][r][k], fun(boxes, l, i, k + 1) + fun(boxes, i + 1, r - 1, 0));
}
}
return dp[l][r][k];
}
};
遍历每一种可能,结果超时了
class Solution {
public:
struct Node{
int val, cnt;
Node(int a, int b): val(a), cnt(b){}
};
int removeBoxes(vector<int>& boxes) {
if(boxes.size() == 0)
return 0;
vector<Node> nums;
nums.push_back(Node(boxes[0], 1));
for(int i = 1; i < boxes.size(); ++i){
if(boxes[i] == nums.back().val)
nums.back().cnt++;
else
nums.push_back(Node(boxes[i], 1));
}
int res = 0;
dfs(nums, res, 0);
return res;
}
void dfs(vector<Node> &nums, int &res, int cur){
//cout << cur << endl;
if(nums.size() == 0){
res = max(res, cur);
return;
}
for(int i = 0; i < nums.size(); ++i){
auto nums_copy = nums;
int c = nums[i].cnt;
if(i > 0 && i + 1 < nums.size() && nums[i - 1].val == nums[i + 1].val){
nums[i - 1].cnt += nums[i + 1].cnt;
nums.erase(nums.begin() + i, nums.begin() + i + 2);
}
else
nums.erase(nums.begin() + i);
dfs(nums, res, cur + c * c);
nums = nums_copy;
}
}
};