《算法设计与分析》第十二周作业
标签(空格分隔): 课堂作业
姓名:李**
学号:16340114
题目:Burst Balloons(https://leetcode.com/problems/burst-balloons/)
题目概要
给定一串数字,每个数字代表一个气球,每个气球都有一个数值。每次扎破一个气球,可以得到该气球左边和右边以及自身数字之积的硬币,若果左/右没有气球,其数值为1。求能拿到的最大硬币数
思路
这个题目可以先从最简单的情况出发,只有一个气球的时候,只能得到该气球数值的硬币数。对于一般情况,即气球不止一个时(下标从i到j)考虑最后一个需要扎破的气球。当这个气球最后被扎破时,其余被扎破的气球都能获得最大的硬币,而扎破最后选定的气球k的收益为
,整段气球的收益为:
用coins[i][j]表示nums[i…j]能获取的最大硬币数。(包含位置i与j),其值为:
特别地,当nums下标越界时,其值为1。对(3)式中的coins[i][k-1],当
时,其值为0(k-1可能越界),coins[k+1][j]同理。
最后的答案为coins[0][nums.size()-1]。
具体实现
用二维数组存储coins的状态。在循环时,要先计算长度小的气球串再到长度大的气球串。注意判断nums与coins的边界状态即可。
心得
这个动态规划问题的关键在于一般情况的硬币数该怎么算。想到只有一个气球时的抉择,把这个抉择推广到一般情况,再稍微琢磨一下,便可求得coins的状态表达式。
源码:
#define leftNum(x) (x==0 ? 1 : nums[x-1])
#define rightNum(x) (x==length-1 ? 1 : nums[x+1])
#define max(a, b) (a>b ? a : b)
class Solution
{
public:
int maxCoins(vector<int>& nums)
{
int length = nums.size();
if (length == 0)
return 0;
int** coins = new int* [length];
for (int i = 0; i < length; ++i)
coins[i] = new int [length];
for (int i = 0; i < length; ++i)
for (int j = 0; j < length; ++j)
coins[i][j] = 0;
for (int segment = 0; segment < length; ++segment)
{
for (int i = 0; i+segment < length; ++i)
{
int j = i + segment;
for (int k = i; k <= j; ++k)
{
int leftCoins = (k==i ? 0 : coins[i][k-1]);
int rightCoins = (k==j ? 0 : coins[k+1][j]);
int lastBurstKCoins = leftNum(i) * nums[k] * rightNum(j) + leftCoins + rightCoins;
coins[i][j] = max(coins[i][j], lastBurstKCoins);
}
}
}
int answer = coins[0][length-1];
for (int i = 0; i < length; ++i)
delete coins[i];
delete coins;
return answer;
}
};