LeetCode:312 戳气球 动态规划

题目描述

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

现在要求你戳破所有的气球。每当你戳破一个气球 i 时,你可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的 left 和 right 代表和 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

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/burst-balloons
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

这题的状态转移比较难想:

问题:在区间[l, r]戳爆所有气球得到的最大值(闭区间,代表下标范围)

在区间[l, r]内找一中间下标mid,戳一个位于mid下标的气球,问题转化为:

  • 先戳爆区间[l, mid-1]的所有气球
  • 再戳爆区间[mid+1, r]的所有气球
  • 这时候中间只剩下下标为mid的气球没爆,戳爆mid气球

在这里插入图片描述
边界情况是:区间只有一个元素:值就是区间左右元素乘以区间内单个元素

状态转移方程:

扫描二维码关注公众号,回复: 9529198 查看本文章
dp[l][r] = dp[l][mid-1] + dp[mid+1][r] + nums[l-1]*nums[mid]*nums[r+1]

因为mid可以选取在区间[l, r]的任意位置,我们需要找到一种取法使得mid最大,作为区间[l, r]的答案,令mid遍历[l, r]中的所有值,选取最大的结果即可

代码

class Solution {
public:
    int dp[509][509] = {0};
    int maxCoins(vector<int>& nums)
    {
        if(nums.size()==0)
            return 0;
        if(nums.size()==1)
            return nums[0];

        nums.insert(nums.begin(), 1);
        nums.insert(nums.end(), 1);
        for(int i=1; i<nums.size()-1; i++)
        {
            dp[i][i] = nums[i-1]*nums[i]*nums[i+1];
        }
        
        for(int l=nums.size()-2; l>=1; l--)
            for(int r=l; r<=nums.size()-2; r++)
                for(int mid=l; mid<=r; mid++)
                    dp[l][r] = max(dp[l][r], dp[l][mid-1] + dp[mid+1][r] + nums[l-1]*nums[mid]*nums[r+1]);
        
        return dp[1][nums.size()-2];
    }
};
发布了171 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104450046