您的位置:首页 > 其它

[leetcode] Burst Balloons

2016-02-25 00:00 295 查看
题目描述:

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
 = 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


这题的分治思想并不是很直观,因为divide并不是可以一次性地将一个问题分成两个子问题。(我们应该跳出分治一定是分成两个子问题的这种思维定势),而且conquer的时候也不是常规意义的合并,而是取max。

不过直接采用递归的思想去思考,还是比较容易的。但写算法的话就可以用DP了,递归会超时。
dp(i, j) = max{dp(i, k) + dp(k, j) + nums[i]*nums[k}*nums[j]}, k = [i+1, j-1]
dp(i,j)表示数组arr[i,j]对应的该问题的最优解,其中arr[i]和arr[j]都是不能被burst的气球。
而上面的递归式右边max大括号里的表达式表示,最后一个burst的气球是第k个时,我们能够得到的最多的硬币的数目。

另外,这里填充dp的方式也不是常规的i从0到n-1,j也从0到n-1,而是按照j与i之间的间隔逐渐增大的对角线的方式进行填充。至于为什么要用这种方式填充,上面的递推式给出了答案。我们要求dp(i,j)时,一定要预先知道i和j之间的任意区间的dp值,而我们如果采用i从0到n-1,j也从0到n-1或者由大到小的迭代方式都没法满足这个条件,即如果i从小到大,j也从小到大,那么求dp(i,j)时,需要用到dp(i,k)和dp(k,j),i<k<h,其中dp(i,k)会在它之前得到,但dp(k,j)就还没计算到,因为k>i。
而经过观察我们发现,dp(i,k)和dp(k,j)的下标区间长度一定比dp(i,j)要小,所以我们可以采用区间长度由小到大的方式进行填充dp数组。

问题想明白了的话,其实代码还是相对比较容易写的。
class Solution {
public:
    int maxCoins(vector<int>& nums) {
        if(0 == nums.size()) return 0;
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        
        int n = nums.size();
        vector<int> col(n, 0);
        vector<vector<int>> dp(n, col);
        
        for(int len = 2; len < n; ++len)
        {
            for(int i = 0; i < n-len; ++i)
            {
                int ret = 0;
                for(int k = i+1; k < i+len; ++k)
                {
                    int tmp = dp[i][k] + dp[k][i+len] + nums[i]*nums[k]*nums[i+len];
                    if(tmp > ret) ret = tmp;
                }
                dp[i][i+len] = ret;
            }
        }
        return dp[0][n-1];
    }
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: