问题描述:
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.
参考博文:https://www.cnblogs.com/grandyang/p/5006441.html
这道题目用暴力求解的话,时间复杂度太高了。
可以用动态规划,dp[i][j]表示开头为i,结尾为j的子数组的最大乘积和。
我们可以尝试找出这个小段里面最后爆破的那一个气球。这个气球要满足的条件是,最后爆破它可以使乘积和最大
max(dp[i][k-1]+dp[k+1][j]+nums[k]*nums[i-1]*nums[j+1]) i<=k<=j
注意:
1、当k=i时,第一项dp[i][i-1]=0;同理,当k=j时,第二项dp[j+!][j]=0
对于dp[i][j]来说,只有当i<=j时才有意义,即非0,所以这个矩阵应该是一个上三角矩阵。
2、第三项应该是nums[k]*nums[i-1]*nums[j+1],因为k是i~j这个子段里剩下的最后一个气球了
3、观察这个动态转移矩阵发现,它需要已知更小长度的子段的最大乘积和,即dp值
所以我们计算dp矩阵的顺序应该是,依次计算长度为1,2,。。。n的子段的dp值
代码如下:
class Solution {
public:
int maxCoins(vector<int>& nums) {
nums.insert(nums.begin(),1);
nums.push_back(1);
int len=nums.size();
vector<int> a(len,0);
vector<vector<int>> dp(len,a);
for(int i=0;i<len;i++)
dp[i][i]=nums[i];
for(int i=1;i<len-1;i++)
for(int j=1;j<=len-2-i+1;j++)
{
int m=j+i-1;
dp[j][m]=max(dp[j+1][m]+nums[j]*nums[j-1]*nums[m+1],dp[j][m-1]+nums[m]*nums[j-1]*nums[m+1]);
for(int k=j+1;k<=m-1;++k)
{
dp[j][m]=max(dp[j][m],dp[j][k-1]+nums[k]*nums[j-1]*nums[m+1]+dp[k+1][m]);
}
}
return dp[1][len-2];
}
};