LeetCode HOT 100 —— 312.戳气球

题目

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

现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。
这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1
超出了数组的边界,那么就当它是一个数字为 1 的气球。

求所能获得硬币的最大数量。
在这里插入图片描述

思路

区间dp:
定义 f[i][j]为考虑将 (i,j)范围内(不包含 ij 边界)的气球消耗掉,所能取得的最大价值。

考虑在开区间内最后一个被戳破的气球k,即k是这个区间内最后一个被戳破的气球,换句话说,目前剩下的气球就是只剩下开区间的首尾ij,以及最后一个被戳破的气球k

假设 dp[i][j] 表示开区间 (i,j) 内能拿到的最多金币   那么这个情况下 ,在 (i,j) 开区间得到的金币可以由 dp[i][k]dp[k][j] 进行转移,如果此时选择戳爆k气球,那么得到的金币就是total = dp[i][k] + val[i] * val[k] * val[j] + dp[k][j],其中val[i] 表示 i 位置气球的数字

也正是因为 k 是最后一个被戳爆的,所以 (i,j) 区间中 k 两边的东西必然是先各自被戳爆了的, 左右两边互不干扰

最后在 (i,j) 区间中选取的k可以是多个,进行一个枚举,从中选择使得 total 值最大的即可用来更新 dp[i][j],然后从 (i,j) 开区间只有三个数字的时候开始计算,储存每个小区间可以得到金币的最大值 然后慢慢扩展到更大的区间,即j不断扩大,利用小区间里已经算好的数字来算更大的区间即可

java代码如下:

class Solution{
	public int maxCoins(int[] nums){
		int n = nums.length;
		//创建一个辅助数组,在首尾各添加1,方便处理边界问题
		int[] temp = new int[n + 2];
		temp[0] = 1;
		temp[n+1] = 1;
		//填充原数组的值
		for(int i = 0; i < n; i++){
			temp[i + 1] = nums[i];
		} 
		int[][] dp = new int[n + 2][n + 2];
		//len表示开区间长度,从(i,k,j)开始循环,逐渐扩大
		for(int len = 3; len <= n + 2; len++){
			for(int i = 0; i <= n + 2 - len; i++){
				int res = 0;
				//k为开区间(i,j)内的索引
				for(int k = i + 1; k < i + len - 1; k++){//范围不断扩大
					int left = dp[i][k];//表示区间(i,k)
					int right = dp[k][i + len -1];//表示区间(k,i + len - 1)
					res = Math.max(res,left + temp[i] * temp[k] * temp[i + len - 1] + right);
				}
				dp[i][i + len - 1] = res;//不断记录开区间的最大金币
			}
		}
		return dp[0][n+1];
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HDU-五七小卡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值