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
Example:
Given [3, 1, 5, 8]
Return 167
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> [] coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
[思路]动态规划。看到题目最容易想到的是采用回溯遍历解,这样复杂度有O(N!)如此高的复杂度肯定通不过时间限制。
于是尝试采用动态规划。
如果我们采用分治法,计算中间爆掉的气球,然后把集合分成两个。但是考虑到气球爆掉之后相邻气球的位置变化了,对最大硬币数有影响,采用分治法似乎不行,如果正向思考很难找到相互之间的规律。
那么我们反相思考从最后一个爆掉的气球开始,你得到的硬币显然和爆掉的气球没有关系。如果我们考虑开始爆掉的气球太过麻烦,如果我们从最后一个爆掉的气球分析,问题就简单了。
Dp[i][j] 表示打破的气球介于i和 j 之间得到的最大硬币数。显然我们要求的是Dp[0][n-1].
我们动态规划从k个长度出发扩展。每次计算k长度的子集。计算k子集的时候,改变中间爆掉气球,求最大解。
代码如下:
class Solution { public: int maxCoins(vector<int>& nums) { int nSize = nums.size()+2; nums.insert(nums.begin(),1); nums.push_back(1); vector<vector<int>> Dp(nSize,vector<int>(nSize,0)); for(int k=3; k<=nSize; ++k){ //从不同长度字解扩展开来 for(int left=0; left<=nSize-k; ++left){//确定左右的边界 int right = left+k-1; for(int i=left+1; i<right; ++i){//确定中间爆掉的 Dp[left][right] = max(Dp[left][right],nums[i]*nums[left]*nums[right]+Dp[left][i]+Dp[i][right]); //Dp计算 } } } return Dp[0][nSize-1]; } };