LeetCode 312. Burst Balloons

这周老师布置的题的主题为divide and conquer,其实发现LeetCode上面这方面的题不是很多,为了拿高分我把所有难度为hard的题都看了一下,最后我选择了一道通过率最高的题(毕竟柿子还是得挑软的捏),也就是今天这一道Burst Balloons。首先我们来看一下题目吧。

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值