[LeetCode] Remove Boxes 移除盒子
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.
刚开始看这道题的时候,感觉跟之前那道Zuma Game很像,于是就写了一个暴力破解的方法,结果TLE了。无奈之下只好上网搜大神们的解法,又看了fun4LeetCode大神写的帖子,之前那道Reverse Pairs就是参考的fun4LeetCode大神的帖子,惊为天人,这次又是这般精彩,大神请收下我的膝盖。那么下面的解法就大部分参考fun4LeetCode大神的帖子来讲解吧。在之前帖子Reverse Pairs的讲解中,大神归纳了两种重现模式,我们这里也试着看能不能套用上。对于这种看来看去都没思路的题来说,抽象建模的能力就非常的重要了。对于题目中的具体场景啊,具体代表的东西我们都可忽略不看,这样能帮助我们接近问题的本质,这道题的本质就是一个数组,我们每次消去一个或多个数字,并获得相应的分数,让我们求最高能获得的分数。而之前那道Zuma Game也是给了一个数组,让我们往某个位置加数字,使得相同的数字至少有3个才能消除,二者是不是很像呢,但是其实解法却差别很大。那道题之所以暴力破解没有问题是因为数组的长度和给定的数字个数都有限制,而且都是相对较小的数,那么即便遍历所有情况也不会有太大的计算量。而这道题就不一样了,既然不能暴力破解,那么对于这种玩数组和子数组的题,刷题老司机们都会优先考虑用DP来做吧。既然要玩子数组,肯定要限定子数组的范围,那么至少应该是个二维的dp数组,其中dp[i][j]表示在子数组[i, j]范围内所能得到的最高的分数,那么最后我们返回dp[0][n-1]就是要求的结果。
那么对于dp[i][j]我们想,如果我们移除boxes[i]这个数字,那么总得分应该是1 + dp[i+1][j],但是通过分析题目中的例子,能够获得高积分的trick是,移除某个或某几个数字后,如果能使得原本不连续的相同数字变的连续是坠好的,因为同时移除的数字越多,那么所得的积分就越高。那么假如在[i, j]中间有个位置m,使得boxes[i]和boxes[m]相等,那么我们就不应该只是移除boxes[i]这个数字,而是还应该考虑直接移除[i+1, m-1]区间上的数,使得boxes[i]和boxes[m]直接相邻,那么我们获得的积分就是dp[i+1][m-1],那么我们剩余了什么,boxes[i]和boxes[m, j]区间的数,此时我们无法处理子数组[m, j],因为我们有些信息没有包括在我们的dp数组中,此类的题目归纳为不自己包含的子问题,其解法依赖于一些子问题以外的信息。这类问题通常没有定义好的重现关系,所以不太容易递归求解。为了解决这类问题,我们需要修改问题的定义,使得其包含一些外部信息,从而变成自包含子问题。
那么对于这道题来说,无法处理boxes[m, j]区间是因为其缺少了关键信息,我们不知道boxes[m]左边相同数字的个数k,只有知道了这个信息,那么m的位置才有意义,所以我们的dp数组应该是一个三维数组dp[i][j][k],表示区间[i, j]中能获得的最大积分,当boxes[i]左边有k个数字跟其相等,那么我们的目标就是要求dp[0][n-1][0]了,而且我们也能推出dp[i][i][k] = (1+k) * (1+k)这个等式。那么我们来推导重现关系,对于dp[i][j][k],如果我们移除boxes[i],那么我们得到(1+k)*(1+k) + dp[i+1][j][0]。对于上面提到的那种情况,当某个位置m,有boxes[i] == boxes[m]时,我们也应该考虑先移除[i+1,m-1]这部分,我们得到积分dp[i+1][m-1][0],然后再处理剩下的部分,得到积分dp[m][j][k+1],这里k加1点原因是,移除了中间的部分后,原本和boxes[m]不相邻的boxes[i]现在相邻了,又因为二者值相同,所以k应该加1,因为k的定义就是左边相等的数字的个数。讲到这里,那么DP方法最难的递推公式也就得到了,那么代码就不难写了,需要注意的是,这里的C++的写法不能用vector来表示三维数组,好像是内存限制超出,只能用C语言的写法,由于C语言数组的定义需要初始化大小,而题目中说了数组长度不会超100,所以我们就用100来初始化,参见代码如下:
解法一:
class Solution {
public:
int removeBoxes(vector<int>& boxes) {
int n = boxes.size();
int dp[][][] = {};
return helper(boxes, , n - , , dp);
}
int helper(vector<int>& boxes, int i, int j, int k, int dp[][][]) {
if (j < i) return ;
if (dp[i][j][k] > ) return dp[i][j][k];
int res = ( + k) * ( + k) + helper(boxes, i + , j, , dp);
for (int m = i + ; m <= j; ++m) {
if (boxes[m] == boxes[i]) {
res = max(res, helper(boxes, i + , m - , , dp) + helper(boxes, m, j, k + , dp));
}
}
return dp[i][j][k] = res;
}
};
下面这种写法是上面解法的迭代方式,但是却有一些不同,这里我们需要对dp数组的部分值做一些初始化,将每个数字的所有k值的情况的积分都先算出来,然后在整体更新三维dp数组的时候也很有意思,并不是按照原有的顺序更新,而是块更新,先更新dp[1][0][k], dp[2][1][k], dp[3][2][k]....,再更新dp[2][0][k], dp[3][1][k], dp[4][2][k]...., 再更新dp[3][0][k], dp[4][1][k], dp[5][2][k]....,之前好像也有一道是这样区域更新的题,但是博主想不起来是哪一道了,以后想起来了再来补充吧,参见代码如下:
解法二:
class Solution {
public:
int removeBoxes(vector<int>& boxes) {
int n = boxes.size();
int dp[n][n][n] = {};
for (int i = ; i < n; ++i) {
for (int k = ; k <= i; ++k) {
dp[i][i][k] = ( + k) * ( + k);
}
}
for (int t = ; t < n; ++t) {
for (int j = t; j < n; ++j) {
int i = j - t;
for (int k = ; k <= i; ++k) {
int res = ( + k) * ( + k) + dp[i + ][j][];
for (int m = i + ; m <= j; ++m) {
if (boxes[m] == boxes[i]) {
res = max(res, dp[i + ][m - ][] + dp[m][j][k + ]);
}
}
dp[i][j][k] = res;
}
}
}
return n == ? : dp[][n - ][];
}
};
类似题目:
参考资料:
https://leetcode.com/problems/remove-boxes/
https://discuss.leetcode.com/topic/84282/memoization-dfs-c
https://discuss.leetcode.com/topic/84687/java-top-down-and-bottom-up-dp-solutions
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Remove Boxes 移除盒子的更多相关文章
- 546 Remove Boxes 移除盒子
给定一些不同颜色的盒子,以不同的正整数表示.消去连续相同颜色的盒子,直到全部消除完毕为止.每一次消去可以得到k * k分(k为消去盒子的个数, k >= 1).计算可以得到的最大得分.注意:盒 ...
- [LeetCode] Remove Element 移除元素
Given an array and a value, remove all instances of that value in place and return the new length. T ...
- [LeetCode] Remove 9 移除9
Start from integer 1, remove any integer that contains 9 such as 9, 19, 29... So now, you will have ...
- [LeetCode] Remove Comments 移除注释
Given a C++ program, remove comments from it. The program source is an array where source[i] is the ...
- [Swift]LeetCode546. 移除盒子 | Remove Boxes
Given several boxes with different colors represented by different positive numbers. You may experie ...
- Leetcode 546.移除盒子
移除盒子 给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色.你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止.每一轮你可以移除具有相同颜色的连续 k 个盒子(k > ...
- Java实现 LeetCode 546 移除盒子(递归,vivo秋招)
546. 移除盒子 给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色. 你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止.每一轮你可以移除具有相同颜色的连续 k 个盒子( ...
- LeetCode:Remove Duplicates from Sorted List I II
LeetCode:Remove Duplicates from Sorted List Given a sorted linked list, delete all duplicates such t ...
- LeetCode:Remove Duplicates from Sorted Array I II
LeetCode:Remove Duplicates from Sorted Array Given a sorted array, remove the duplicates in place su ...
随机推荐
- Oracle查询优化改写--------------------操作多个表
一.union all与空字符串 二.组合相关行 三.in .exists.inter join .left join .right join .full join 之间的区别 'inner joi ...
- 微信公众平台开发,API接入与推送事件(1)
博客好久没有更新了,今天说说微信开发.微信开发的好多初学者都会又这样的迷惑,微信开发到底是什么?其实微信开发本质我和我们的网站开发没有太大的区别.我们常说的微信开发也就是公众号开,微信公众号分为三个类 ...
- 福州大学软工1715|W班-启航
新的一学期即将开启,而在仅剩的几天的时间内,我将为接下来的软工实践助教事宜忙碌起来.要学习的东西很多,要关注的东西也很多. 虽然我现在还在茫然阶段,虽然我对<构建之法>还不太熟悉,但是,我 ...
- 听翁恺老师mooc笔记(3)--指针的定义
在上一个blog学习了&运算符,使用&取了变量.数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(&q ...
- Alpha第四天
Alpha第四天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...
- 基于scrapy爬虫的天气数据采集(python)
基于scrapy爬虫的天气数据采集(python) 一.实验介绍 1.1. 知识点 本节实验中将学习和实践以下知识点: Python基本语法 Scrapy框架 爬虫的概念 二.实验效果 三.项目实战 ...
- 基于协程的Python网络库gevent
import gevent def test1(): print 12 gevent.sleep(0) print 34 def test2(): print 56 gevent.sleep(0) p ...
- NATAPP 内网映射,Visual Studio ,C# 实现本地开发微信公众号,本地调试无需服务器
点击软件安装教程,根据安装教程,注册帐号,下载软件,配置软件.配置完后如下图,途中红色位置免费版本是随机的. 红色位置是自己的映射域名. 打开VS,并且打开项目,右键项目,在web 选项中修改项目UR ...
- kubernetes入门(08)kubernetes单机版的安装和使用
kubectl get - 类似于 docker ps ,查询资源列表 kubectl describe - 类似于 docker inspect ,获取资源的详细信息 kubectl logs - ...
- 云计算(2)it 是什么
2015年,全世界在it上面的花费达到3亿8千亿美金之多. 云数据中心:核心基础架构,云计算的物理载体,提供数据处理.存储和高性能计算支撑,包括服务器.存储.冷却.机房空间和能耗管理等. 超大规模的云 ...