leetcode312Burst Balloons
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这道题对我个人感觉还是很难的,对于分而治之和动态规划的敏感度低,使用起来也很拙计,于是翻遍了各种解答方案,终于有了自己的一点小小的领悟。
首先将原来的数组的头尾分别添加2个值为1的元素,是数组维数变为n+2。之后创建一个空的全为0的二维数组,维数为n+2 x n+2。
这个二维数组用来保存每个小段中的最大硬币数量,比如result[1][5]即代表从第1个灯泡开始直到第5个灯泡这个区间中,最大的硬币数量。之后我们需要定义区间的长度len,和开始结束点位置start和end。最大长度从1开始,遍历到n,起始位置从1开始直到,n - len + 1为止,结束位置也可以相应的计算出来。此时每次遍历的时候,我们需要求的就是result[start][end]值,然后一步步递推,求出最后的结果result[1][n]就是整个区间的最大硬币数量。其实之前的步骤都很好理解,最重要的就是动态规划的递推公式了,如下
result[start][end] = max(result[start][end], result[start][i-1] + result[i+1][end] + nums[start-1]*nums[i]*nums[end+1]);
我一开始就是在这个地方愣住了,不懂什么意思,后来自己琢磨了一番,有了理解。其中i是在start和end之间的,是假设作为最后一个被熄灭的灯泡的位置,然后在start和end之间分别选取每个位置作为最后灯泡灭掉的位置,分别求值,将最大值保存在result[start][end]中,即这段区间硬币最大的数量。此时假设start = 1, end = 4, i刚好遍历到2,根据递推公式,如果是第2个灯泡最后灭的话,求的硬币数量应该是result[1][1] + result[3][4] + nums[0]*nums[2]*nums[5],看到这里,是不是有点了解了,区间为1-4,第二个灯泡最后灭的话,首先区间1-1的硬币数量,区间3-4的硬币数量,必须加起来,然后由于率先灭了2左右的灯泡,所以最后剩下的左右两边分别是nums[0]和nums[5]与nums[2]的乘积,相加,才是最后灭掉灯泡2的最大硬币数量。之后的就是依次遍历,保留最大值。所以关键看懂一个算法还是需要自己不断去试,去在纸上写写画画才有最深刻的体会,很关键,好吧。
编辑下,忘记贴代码了。。。。
class Solution {
public:
int maxCoins(vector<int>& nums) {
int n = nums.size();
nums.insert(nums.begin(), 1);
nums.insert(nums.end(), 1);
vector<vector<int> > result(nums.size(), vector<int>(nums.size(), 0));
int len, start, end;
for (len = 1; len <= n; ++len)
{
for (start = 1; start <= n - len + 1; ++start)
{
end = start + len - 1;
for (int i = start; i <= end; ++i)
{
result[start][end] = max(result[start][end], result[start][i-1] + result[i+1][end] + nums[start-1]*nums[i]*nums[end+1]);
}
}
}
return result[1][n];
}
};