【leetcode】312 戳气球(动态规划)

题目链接:https://leetcode-cn.com/problems/burst-balloons/

题目描述

有 n 个气球,编号为0 到 n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中。

现在要求你戳破所有的气球。每当你戳破一个气球 i 时,你可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的 leftright 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球。

求所能获得硬币的最大数量。

说明:

  • 你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

示例:

输入: [3,1,5,8]
输出: 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

思路

1 暴力
// 1 暴力法
// 超时
class Solution {
public:
    int maxCoins(vector<int>& nums) {
        if(nums.empty()) return 0;
        int n = nums.size();
        nums.insert(nums.begin(), 1);   // 开头和结尾补1
        nums.insert(nums.end(), 1);
        return helper(nums, 1, n);
    }

private:
    int helper(vector<int>& nums, int l, int r){
        if(l >= r)
            return nums[l-1] * nums[l] * nums[r+1];
        // 最后打爆nums[l]的方案与最后打爆nums[r]的方案先比
        int ret = max(nums[l-1] * nums[l] * nums[r+1] + helper(nums, l+1, r),
                      nums[l-1] * nums[r] * nums[r+1] + helper(nums, l, r-1));
        // 尝试中间位置气球被最后打爆的每一种方案
        for (int i = l+1; i <r ; ++i)
            ret = max(ret, nums[l-1] * nums[r+1] * nums[i] + helper(nums, l, i-1) + helper(nums, i+1, r));
        return ret;
    }
};
2 动态规划

dp[i][j]表示从l位置到r位置的最大分数

// 2 动态规划
// 时间复杂度O(n^3) 空间复杂度O(n^2)
class Solution {
public:
    int maxCoins(vector<int>& nums) {
        if(nums.empty()) return 0;
        if(nums.size() == 1) return nums[0];
        int n = nums.size();
        nums.insert(nums.begin(), 1);   // 开头和结尾补1 避免判断越界
        nums.insert(nums.end(), 1);
        vector<vector<int>> dp(n+2, vector<int> (n+2, 0));
        for (int i = 1; i <=n ; ++i) {
            dp[i][i] = nums[i-1] * nums[i] *nums[i+1];  // 初始化区间大小为1的dp值
        }
        // 从下往上 从左往后迭代计算
        // dp[l][r]值值依赖同一行左边dp[][r-1]和同一列下边dp[l+1][]的有效位置
        for (int l = n; l >= 1 ; --l) {
            for (int r = l+1; r <= n ; ++r) { // 注意只有 r>= l才有效
                // 求解dp[l][r], 表示戳nums[l..r]所有气球的最大分数
                int finalL = nums[l-1] * nums[r+1] * nums[l] + dp[l+1][r];
                int finalR = nums[l-1] * nums[r+1] * nums[r] + dp[l][r-1];
                // 最后打爆nums[l]的方案与最后打爆nums[r]的方案先比
                dp[l][r] = max(finalL, finalR);
                for (int i = l+1; i < r; ++i) {
                    // 尝试中间位置气球被最后打爆的每一种方案
                    dp[l][r] = max(dp[l][r], nums[l-1] * nums[r+1] * nums[i] + dp[l][i-1] + dp[i+1][r]);
                }
            }
        }
        return dp[1][n];
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值