Burst Balloons

406 篇文章 0 订阅
406 篇文章 0 订阅

1,题目要求

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:

  • 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

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

给定n个气球,索引从0到n-1。 每个气球都涂有一个由数组nums表示的数字。 你被要求爆破所有的气球。 如果你爆裂气球我会得到nums [left] * nums [i] * nums [right]coin。 这里左边和右边是i的相邻指数。 在爆发之后,“左”和“右”然后变得相邻。

通过明智地爆破气球找到可以收集的最大硬币。

2,题目思路

对于这道题,要求给定一系列的气球,气球中有不同数目的硬币,每次爆照一个气球,可以获得当前爆炸的气球的硬币数乘以左右气球的硬币数,求出爆炸气球的顺序,使得获得的硬币数目最多。

在这里,我们使用动态规划的策略来解决这个问题。我们维护一个二维动态数组 dp,其中 dp[i][j] 表示打爆区间 [i,j] 中的所有气球能得到的最多金币。

题目中说明了边界情况,当气球周围没有气球的时候,旁边的数字按1算,这样我们可以在原数组两边各填充一个1,方便于计算。

对于区间[i, j],如果我们知道了所有的小区间的 dp 值,那么就可以逐步获得[i, j]的值。
此时,遍历这个区间内的每个气球,设置k在区间 [i, j] 中,假如第k个气球最后被打爆,那么此时区间 [i, j] 被分成了三部分,[i, k-1],[k],和 [k+1, j],只要我们之前更新过了 [i, k-1] 和 [k+1, j] 这两个子区间的 dp 值,可以直接用 dp[i][k-1] 和 dp[k+1][j],那么最后被打爆的第k个气球的得分该怎么算呢,你可能会下意识的说,就乘以周围两个气球被 nums[k-1] * nums[k] * nums[k+1],但其实这样是错误的!dp[i][k-1] 的意义是什么呢,是打爆区间 [i, k-1] 内所有的气球后的最大得分,此时第 k-1 个气球已经不能用了,同理,第 k+1 个气球也不能用了,相当于区间 [i, j] 中除了第k个气球,其他的已经爆了,那么周围的气球只能是第 i-1 个,和第 j+1 个了,所以得分应为 nums[i-1] * nums[k] * nums[j+1],如下所示:

dp[i][j] = max(dp[i][j], nums[i - 1] * nums[k] * nums[j + 1] + dp[i][k - 1] + dp[k + 1][j])                 ( i ≤ k ≤ j )

参考博客地址:
[LeetCode] Burst Balloons 打气球游戏

3,代码实现

static const auto s = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        int N = nums.size();
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        
        vector<vector<int>> dp (N+2, vector<int>(N+2, 0));
        for(int len = 1;len <= N;len++){
            for(int i = 1;i <= N - len + 1;i++){
                int j = i + len - 1;
                for(int k = i;k <= j;k++)
                    dp[i][j] = max(dp[i][j], dp[i][k-1]+nums[i-1]*nums[k]*nums[j+1]+dp[k+1][j]);
            }
        }
        return dp[1][N];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值