心情:一如既往,只要困难就凉凉…
题目描述:
有 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 = 315 + 358 + 138 + 181 = 167
思考:
这种题目要怎么能联想到动态规划呢?
首先它不是求某个子集,我觉得一般求某个子集都是回溯,
之后递归我确实也想不到…那就动态规划吧!!!
思路:
1.动态规划一般是dp[i][j] ,这个在这提代表的是什么?
i 和 j 代表的是一个范围,即某个范围的最优解,即在这个范围内戳破气球的最大值。
2.如何求这个范围内的最大值?
从这个范围的值一个个遍历(不包括边界),每次选定的值m,即为这个范围最后一个被戳破的气球!!!那么最后一次戳破气球的值为:
nums[i] x nums[j] x nums[m]
(因为在 i 到 j 之间的气球(除了m)都被戳破了,所以乘的是边界值)
,之后我们并不关心这个k之前 i 到 m 的最大值和 m 到 j 的最大值,因为这个范围比当前小,我们实际上已经在前面已经算出来,所以直接:
dp[i][m]+dp[m][j]+nums[i] x nums[j] x nums[m]
求出这个范围内的最大值。
3.最后注意填充边界,为了方便计算!!
class Solution {
public:
int maxCoins(vector<int>& nums) {
int nsize = nums.size();
nums.insert(nums.begin(),1);
nums.push_back(1);
int dp[nsize+2][nsize+2];
for(int i = 0;i < nsize+2;i++){
for(int j = 0;j < nsize+2;j++){
dp[i][j] = 0;
}
}
for(int b = 2;b <= nsize+1;b++){
for(int i = 0;i <= nsize-b+1;i++){
int j = i+b;
for(int m = i+1;m < j;m++){
dp[i][j] = max(dp[i][j],dp[i][m]+dp[m][j]+nums[i]*nums[j]*nums[m]);
}
}
}
return dp[0][nsize+1];
}
};
未完待续…