算法设计与分析(十):DP

Burst 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.

Example:

Input: [3,1,5,8]
Output: 167 
Explanation: 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

Note:

  • You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

如题意,戳破一个气球,就会得到该气球中的数值与其相邻气球中数值的乘积数量的硬币,然后气球会被破坏。本题要求按怎样的顺序戳气球,会使得得到的硬币总数最多?

显然,我们可以采取DP的思路,假设某个气球最后被戳破,,然后假设在它之上是哪个气球被戳破。。。列举出所有的可能,去其中的最大值,自然可以得解。然而这种直接DP的方式的时间复杂度在O(n!)级别,非常的高。有没有更好的办法呢?

我们可以发现,其实每次求解的过程是类似的,我们可以尝试使用“分而治之”的思想。如何划分子过程呢?如果按照当前戳破的气球划分的话,戳破后产生的相邻气球会被分割到左右两个子过程中,而这显然是不行的。

我们应该以最后被戳破的气球来划分。为什么呢?因为以最后被戳破的气球来划分,不会将相邻的气球分割到左右两个子过程中(因为它已经是最后一个剩下的气球了)。

按照题目要求,序列的左右应该还有两个值为1 的“虚拟气球”, 便于我么进行乘法运算,则需要修改一下原数组:

nums.insert(nums.begin(),1);
nums.insert(nums.end(),1);

新建一个二维数组dp,其中的值dp[i][j]代表了从数组中的i到j的子数组中可以得到的最大硬币数:

vector<vector<int>> dp(nums.size(),vector<int>(nums.size(),0));

附上完整完整代码:

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int N = nums.size();
        if(N == 0) return 0;
        nums.insert(nums.begin(),1);
        nums.insert(nums.end(),1);
        
        vector<vector<int>> dp(nums.size(),vector<int>(nums.size(),0));
        
        for(int len = 1; len <= N; len ++) {
            for(int left = 1; left <= N - len + 1; left ++) {
                int right = left + len - 1;
                for(int i = left;i <= right; i ++) {
                    dp[left][right] = max(dp[left][right],nums[left-1]*nums[i]*nums[right+1] + dp[left][i-1]+dp[i+1][right]);
                }
            }
        }
        return dp[1][N];
    }
};

附上LeetCode链接:https://leetcode.com/problems/burst-balloons/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值