leetcode刷题,总结,记录,备忘 312

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];
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值