Given n
balloons, indexed from 0
to n-1
. Each balloon is painted with a number on it represented by array nums
. You are asked to burst all the balloons. If the you burst balloon i
you will get nums[left] * nums[i] * nums[right]
coins. Here left
and right
are adjacent indices of i
. After the burst, the left
and right
then becomes adjacent.
Find the maximum coins you can collect by bursting the balloons wisely.
Note:(1) You may imagine
nums[-1] = nums[n] = 1
. They are not real therefore you can not burst them.(2) 0 ≤ n
≤ 500, 0 ≤ nums[i]
≤ 100
其实第一眼看到这道题我的想法是这道题应该放到动态规划里面,我们来翻译一下题目,老规矩,英语自认为比我好的读者请自行翻译。大概意思是有n个气球,编号从0到n-1,每个气球上有一个数字,所有气球上的数字连起来就是一个数组了,也就是代码中将会给出的向量nums,现在给你一根针,去戳爆这些气球,每戳爆一个气球,你将得到气球上数字乘上它相邻气球上数字的硬币,那么问题来了,你能拿到的最多的硬币是多少?个人觉得做人不能太贪心,随便戳就好,这可是按乘法计算的啊,花半个小时写程序算最多拿多少,我早就戳了好几轮了,分分钟发家致富啊。言归正传,下面开始正式的题解。
既然主题是divide and conquer,分而治之的概念这里就不再赘述,自行百度,大概意思就是把一个大问题分解成一个个容易解决的小问题,比如说你想要建一栋高楼,按照分治的思想,你应该将这个大目标分解成若干小目标,比如先挣他一个亿.......好吧,你应该一层一层的建,那么再分解一下呢?一间房一间房的建。那么最容易的小目标是什么呢?一块砖一块砖地砌。分治大概就是这么一种思想了。如果说错了请不要打我。
那么针对这一道题我们需要怎么来应用分治呢?我们来实际模拟一下,假如给出的数列是3,1,5,8,我个人比较喜欢5,所以我们先把5去掉,得到新的数列3,1,8,你会发现问题回到了最初的那个问题,只是数据量从4变成了3,如果你看到这里就豁然开朗,迫不及待去亲身实践的话我只能说too naive。当然这样去想是没有什么大错误,只是时间开销将会异常大,你将写大量代码来处理向量数据的问题,而不是核心算法。我这么模拟只想告诉你越到后面数据量越小,如果说我最后只剩三个气球,你可以一眼就看出来答案,所以我们所需要做的就是逆向思维,从最后面倒推。
那么现在有这么一排气球我们要怎么做呢?首先我们要知道最后会剩下三个气球,left,mid,right,按照题目提示,left 和right这两个气球上的数字都为1且不能戳爆,那么其他气球到这一步已经是全部都已经戳爆了,并且这些气球是在left到mid之间和mid到right之间的。有趣的部分来了,这两个子序列是不是相同的两个子问题呢?答案是肯定的,按照同样的方法分析就可以解决。 下面是解题代码:
class Solution {
public:
int maxCoins(vector<int>& nums) {
vector<int>nnums;//根据题目提示新建向量,把首尾的1加入数组
nnums.push_back(1);
for(int i=0;i<nums.size();i++)
nnums.push_back(nums[i]);
nnums.push_back(1);
int c[505][505];//表示从a到b这一区间内能得到硬币的最大值
memset(c,0,sizeof(c));
int ans=gans(c,0,nnums.size()-1,nnums);
return ans;
}
int gans(int c[][505],int b,int e,vector<int>n)
{
if(b+1==e)
return 0;
if(c[b][e]>0)
return c[b][e];
int coin=0;
for(int i=b+1;i<e;i++)//dp部分,从起始点到终点遍历一遍求得最大值
{
coin=max(coin,n[b]*n[e]*n[i]+gans(c,b,i,n)+gans(c,i,e,n));//左右两子序列的最优解加上两边界和mid的乘积即为能得到的金币
}
c[b][e]=coin;//记忆化搜索
return coin;
}
};
代码思路还是比较清晰吧,注释也很完整,最后使用了一下记忆化搜索,可以节省时间开销。这次的题解大概就是这样了,thanks for reading!
-------------------------------------手动分割线--------------------------------------
see you next illusion