题目描述
有 n 个气球,编号为0 到 n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。每当你戳破一个气球 i 时,你可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的 left 和 right 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球。
求所能获得硬币的最大数量。
说明:
你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。
0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
示例:
输入: [3,1,5,8]
输出: 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
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/burst-balloons
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
这题的状态转移比较难想:
问题:在区间[l, r]
内戳爆所有气球得到的最大值(闭区间,代表下标范围)
在区间[l, r]
内找一中间下标mid
,戳一个位于mid
下标的气球,问题转化为:
- 先戳爆区间
[l, mid-1]
的所有气球 - 再戳爆区间
[mid+1, r]
的所有气球 - 这时候中间只剩下下标为mid的气球没爆,戳爆mid气球
边界情况是:区间只有一个元素:值就是区间左右元素乘以区间内单个元素
状态转移方程:
dp[l][r] = dp[l][mid-1] + dp[mid+1][r] + nums[l-1]*nums[mid]*nums[r+1]
因为mid
可以选取在区间[l, r]
的任意位置,我们需要找到一种取法使得mid最大,作为区间[l, r]的答案,令mid遍历[l, r]
中的所有值,选取最大的结果即可
代码
class Solution {
public:
int dp[509][509] = {0};
int maxCoins(vector<int>& nums)
{
if(nums.size()==0)
return 0;
if(nums.size()==1)
return nums[0];
nums.insert(nums.begin(), 1);
nums.insert(nums.end(), 1);
for(int i=1; i<nums.size()-1; i++)
{
dp[i][i] = nums[i-1]*nums[i]*nums[i+1];
}
for(int l=nums.size()-2; l>=1; l--)
for(int r=l; r<=nums.size()-2; r++)
for(int mid=l; mid<=r; mid++)
dp[l][r] = max(dp[l][r], dp[l][mid-1] + dp[mid+1][r] + nums[l-1]*nums[mid]*nums[r+1]);
return dp[1][nums.size()-2];
}
};