312. 戳气球(区间dp)

article/2025/9/10 15:54:11

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

  • 首先这个长度为500的范围可以猜测出是O(n^3)区间dp
  • 这里主要讲述为什么状态定义要定义成开区间而不是闭区间

最大的原因:闭区间计算出来的状态是无法保证正确性的

假如使用一开始的闭区间定义去做:原先定义dp[i,j]:戳爆i~j下标气球的最大积分。

举一个样例:nums = [3,1,5,8]
(以下标开始为1进行讲述)

枚举k作为区间内最后一个被戳爆的气球,那么此时若最后一下要戳爆k,若想让k成为最后一下,则绿色部分要先消去完。

先考虑计算k为最后一个戳爆产生的积分,nums[i]*nums[k]*nums[j],但是不止。因为此时戳爆后在[i,j]状态定义消去[i,j]所有气球,所以剩下的还有i,j两个气球的答案,因此如此定义这部分积分为:

 LL a = nums[k] * (nums[l] + nums[r]) + max(nums[l], nums[r]);LL b = nums[k] * nums[l] * nums[r] + nums[l] * nums[r] + max(nums[l], nums[r]); 

我们再来看绿色部分:看起来直接加上dp[i+1,k-1]和dp[k+1,j-1]就行了。

那么dp[i+1,j-1]计算的时候是怎么计算的呢?

考虑绿1部分要消去完,肯定保证绿1要有最后一个被戳爆的气球,而该气球产生的积分要依赖nums[i]和nums[k],分数为nums[x]*nums[i]*nums[k]。

也就是说我们现在计算dp[i,j]的时候要nums[i]和nums[j]的贡献,而dp[i+1,k-1]也要nums[i]和nums[j]的贡献,那我们dp[i+1,k-1]的这个答案就不是独立子问题的,和当前求解的状态仍然有共同的计算部分。

所以这个状态定义是有问题的。
在这里插入图片描述
具体来说:在计算[3,1,5,8]时,nums[k]=5时,计算出的结果为:1+0+3x8x5+3x8+8=152,这里可以发现少算,少算的部分是什么呢?我们看到计算dp[2][2]的时候答案是0,但是在实际上这个nums[2]=1戳破的时候是可以有旁边3x5的累加积分的,但是我们没算。这里就是问题。

而如果定义成开区间就没这样的问题。
当计算dp[i][j]的时候,nums[i]和nums[j]保证没有被戳破,而dp[i][k]的计算时保证nums[i+1]和nums[k-1]也存在,此时dp[i][j]通过dp[i][k]这部分直接转移过来是没有问题的,而且nums[k]的贡献直接和nums[i],nums[j]相乘即可。
在这里插入图片描述

typedef long long LL;
class Solution {
public:static const int maxn = 510;LL dp[maxn][maxn];int maxCoins(vector<int>& nums) {int n = static_cast<int>(nums.size());nums.insert(nums.begin(), 1);nums.push_back(1);for (int i = 1; i <= n; i++) {dp[i][i] = nums[i];//dp[i][i] = nums[i - 1] * nums[i] * nums[i + 1];dp[i][i+1] = nums[i] * nums[i + 1] + max(nums[i], nums[i + 1]);    }for (int len = 3; len <= n; len++) {for (int l = 1; l + len - 1 <= n; l++) {int r = l + len - 1;//dp[l][r] = max(dp[l][r], nums[l - 1] * nums[l] * nums[r] + dp[l + 1][r - 1]);//dp[l][r] = max(dp[l][r], nums[r + 1] * nums[r] * nums[l] + dp[l + 1][r - 1]);for (int k = l + 1; k < r; k++) {LL a = nums[k] * (nums[l] + nums[r]) + max(nums[l], nums[r]);LL b = nums[k] * nums[l] * nums[r] + nums[l] * nums[r] + max(nums[l], nums[r]); dp[l][r] = max(dp[l][r], dp[l + 1][k - 1] + dp[k + 1][r - 1] + max(a, b));//cout << "dp["<<l<<"]"<<"["<<r<<"]="<<dp[l][r]<<endl;}}}return dp[1][n];//return dfs(0, n, nums);}
};

因此修改为开区间,dp状态转移就合理了。

typedef long long LL;
class Solution {
public:static const int maxn = 510;LL dp[maxn][maxn];int maxCoins(vector<int>& nums) {nums.insert(nums.begin(), 1);  nums.push_back(1);int n = static_cast<int>(nums.size());for (int len = 3; len <= n; len++) {for (int l = 0; l + len - 1 < n; l++) {int r = l + len - 1;for (int k = l + 1; k < r; k++) {dp[l][r] = max(dp[l][r], dp[l][k] + dp[k][r] + nums[l] * nums[r] * nums[k]);//cout << "dp["<<l<<"]"<<"["<<r<<"]="<<dp[l][r]<<endl;}}}return dp[0][n - 1];}
};

http://chatgpt.dhexx.cn/article/dnTac2lX.shtml

相关文章

Python 算法戳气球

戳气球 题目描述&#xff1a; 有 n 个气球&#xff0c;编号为0 到 n - 1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球&#xff0c;你可以获得 nums[i - 1] * nums[i] * nums[i 1] 枚硬币。 这里…

1012-戳气球

题目如下 有 n 个气球&#xff0c;编号为0 到 n - 1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球&#xff0c;你可以获得 nums[i - 1] * nums[i] * nums[i 1] 枚硬币。 这里的 i - 1 和 i 1 代…

戳气球和布尔运算问题(巨难)

一.大气球的最大得分 1.对应letecode链接 打气球的最大分数_牛客题霸_牛客网 (nowcoder.com) 2.题目描述&#xff1a; 3.解题思路 本题个人觉得本题巨难&#xff1a;主要步骤如下&#xff1a; 1.预处理&#xff1a;为便于处理&#xff0c;可在 nums 数组两端各添加一个哨兵 1&…

经典动态规划:戳气球问题

点击上方蓝字设为星标 东哥带你手把手撕力扣~ 作者&#xff1a;labuladong 公众号&#xff1a;labuladong若已授权白名单也必须保留以上来源信息 今天我们要聊的这道题「Burst Balloon」和之前我们写过的那篇 经典动态规划&#xff1a;高楼扔鸡蛋问题 分析过的高楼扔鸡蛋问题类…

*312戳气球

​​​​​​戳气球 有 n 个气球&#xff0c;编号为0 到 n - 1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球&#xff0c;你可以获得 nums[i - 1] * nums[i] * nums[i 1] 枚硬币。 这里的 i - 1 …

力扣---戳气球

力扣—戳气球 文章目录 力扣---戳气球一、题目描述二、回溯思路三、动态规划思路四、代码 一、题目描述 有 n 个气球&#xff0c;编号为0 到 n-1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。每当你戳破一个气球 …

【LeetCode】312. 戳气球

312. 戳气球&#xff08;困难&#xff09; 解法一&#xff1a;动态规划 首先看一个区间&#xff1a; 区间(i,j) 是一个开区间&#xff0c;因为我们只能戳爆 i 和 j 之间的气球&#xff0c;不能戳爆索引为 i 和 j 的气球。 我们不妨考虑该区间内被戳爆的最后一个气球&#xff…

LeetCode312:戳气球

要求 有 n 个气球&#xff0c;编号为0 到 n - 1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球&#xff0c;你可以获得 nums[i - 1] * nums[i] * nums[i 1] 枚硬币。 这里的 i - 1 和 i 1 代表和…

【动态规划】LeetCode 312. 戳气球 --区间DP问题

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

Golang每日一练(leetDay0105) 最小高度树、戳气球

目录 310. 最小高度树 Minimum Height Trees &#x1f31f;&#x1f31f; 312. 戳气球 Burst Balloons &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一…

Leetcode.312 戳气球

题目链接 Leetcode.312 戳气球 题目描述 有 n个气球&#xff0c;编号为0到 n - 1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums中。 现在要求你戳破所有的气球。戳破第 i 个气球&#xff0c;你可以获得 n u m s [ i − 1 ] ∗ n u m s [ i ] ∗ …

LeetCode 312. 戳气球(Java)

题目 有 n 个气球&#xff0c;编号为0 到 n - 1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球&#xff0c;你可以获得 nums[i - 1] * nums[i] * nums[i 1] 枚硬币。 这里的 i - 1 和 i 1 代表和…

每日一道算法题(3)--戳气球问题

题目 戳气球问题 :输入一个包含非负数整数的数组nums代表一排气球, nums[i]代表第i个气球的分数。现在, 你要戳破所有的气球,请计算出最高的分数。 分数的计算规则比较特别&#xff0c;当戳破第i个气球时, 可以获得nums[left] * nums[right] * nums[i]的分数&#xff0c;其中nu…

【leetcode】312.戳气球 (超详细解析,动态规划)

312. 戳气球 难度困难 有 n 个气球&#xff0c;编号为0 到 n-1&#xff0c;每个气球上都标有一个数字&#xff0c;这些数字存在数组 nums 中。 现在要求你戳破所有的气球。如果你戳破气球 i &#xff0c;就可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的 lef…

戳气球问题

戳气球问题本质上可以认为是一种组合逆推的问题&#xff08;背包问题模型&#xff09; 我们可以有两种方法 1.dfs爆搜法 2.dp法 1.dfs爆搜法 dfs爆搜就是暴力枚举出哪个先破&#xff0c;哪个后破&#xff0c;直到找出最佳的方案 本质上是一个全排列问题&#xff0c;但是全…

Linux修改主机名—主机名和IP映射

一、修改主机名 /etc/sysconfig/network 二、主机名和IP映射 /etc/hosts Windows 里面的路径&#xff1a;C:\Windows\System32\drivers\etc

Linux系统下如何修改主机名

Linux系统安装好后&#xff0c;都会有默认的主机名&#xff0c;这里以CentOS系统为例&#xff0c;默认的主机名为localhost.localdomain&#xff0c;为了便于使用&#xff0c;我们常常需要修改主机名&#xff0c;下面演示的是永久更改主机名的方法。 方法/步骤 以根用户登录&a…

杂记 | Linux修改主机名(不用重启)

新买的云服务器主机名比较奇怪。强迫症难受&#xff0c;于是想通过Linux命令修改主机名&#xff0c;且选择最轻松的方案&#xff08;不想重启系统&#xff09;&#xff0c;使用以下命令即可&#xff1a; hostnamectl set-hostname 主机名 systemctl restart systemd-hostnamed…

修改Linux的主机名

修改主机名 新申请下来的设备&#xff0c;修改root后面的主机名为一连串的字符和数字用于centos7.X&#xff0c;其他版本未验证 修改主机名 hostnamectl set-hostname Test_Server1修改后可查看是否修改成功 cat /etc/hostname也可以通过修改hostname文件修改主机名未生效可…

Linux 永久修改主机名(转载)

Linux修改主机名&#xff0c;永久生效。 linux查看主机名: 查看主机命令&#xff1a; [rootlinux_epm2 ~]# hostname localhost.localdomain localhost.localdomain即为默认的主机名。 修改network文件: 用root用户登录&#xff0c;如果不是root用户&#xff0c;使用su命令切换…