打爆一排气球,你能获得的最大分数是多少?

提示:题难没关系,见过一遍总比完全没见过的好,见过的话,再复习一遍,也就很快想起来了。


文章目录

  • 打爆一排气球,你能获得的最大分数是多少?
    • @[TOC](文章目录)
  • 题目
  • 一、审题
  • 二、解题
  • 总结

题目

有一个数组arr,arr[i]代表气球的分数,打爆气球i,意味着你能得一个[i-1]×[i]×[i+1]的分数score_i,你任意选取一个顺序,把所有的气球打爆,累计score_i的最大分数是多少?
当左边,或者右边没有气球的时候,分数是1×[i],或者[i]×1


一、审题

示例:325
(1)顺序1:012位置
——打3,得分为:1×3×2=6,气球剩下:25
——打2,得分为:1×2×5=10,气球剩下:5
——打5,得分为:1×5×1=5,气球剩下:
分数累加和为21分
(2)顺序2:102
——打1,得分为:3×2×5=30,气球剩下:35
——打3,得分为:1×3×5=15,气球剩下:5
——打5,得分为:1×5×1=5,气球剩下:
分数累加和为50分
自然顺序(2)要比(1)更大,我们要50
(3)别的顺序,你也要算出来,然后更新max分数


二、解题

这个题目,首先,0的左边没有球,权值肯定是1,,N-1位置右边没有球,权值也是1,还不如先处理一下arr
让help为N+2长度的数组
然后0和N+1放1,中间1–N为arr数组
像这样:

好,怎么求这个最大分数呢?
定义一个暴力递归代码:f(help,L,R)
打爆L–R范围上的气球,能得到的最大分数是多少?【隐含条件就是L-1和R+1位置这俩球是没有爆炸的,否则你没有办法算分数了】
那就要分几种情况了:
(1)先打爆L,得到一个分数[L-1][L][L+1],然后还需要+f(L+1,R)
下次探索f(L+1,R)时,你L那已经爆了,应该×1了吧,但是,你既然是递归同一个函数f(help,L,R),我们要求隐含条件就是L-1和R+1位置这俩球是没有爆炸的,否则你没有办法算分数了,你现在L都爆了,对于f(L+1,R)来说,你这个隐含条件根本没有满足!这么干不行的。

既然要保住隐含条件,不妨设我们后打爆谁?
(1)最后打爆L,那你L+1–R上已经先被打爆了,自然左边L-1没有被打爆,且右边那个没有被打爆的就是R+1,得到的分数是
[L-1][L][R+1]+f(help,L+1,R) ;

(2)最后打爆R,那你L–R-1上已经先被打爆了,自然左边L-1没有被打爆,且右边那个没有被打爆的就是R+1,得到的分数是
[L-1][R][R+1]+f(help,L,R-1)

(3)让L+1–R-1上任意一个位置i最后被打爆呢,也就是先打爆L–i-1和i+1–R上的气球,那得到的分数,自然是枚举:每一个i
f(help,L,i-1)+[i-1][i][i+1]+f(help,i+1,R)

然后我们要谁,要上面三种情况的max

主函数怎么调用呢,
因为处理过了arr为help,故直接调用f(help,1,N)即可,代表打爆1–N范围上的这N个气球,可以得到的最大分数是多少?

//假设f(L,R)是打爆所有L--R上的气球,能得到的最大的分数是多少呢???不妨设L-1和R+1一直没有被打爆,还在//本身递归打爆L--R就是意味着外面的还存在//恰好arr0和N-1整俩位置左右没有,就乘1,不妨给它加上算了[1,nums,1]这样的话,调用f(1,N)永远都有左边右边1没有爆炸public static int f(int[] nums, int L, int R){//基本情况,当L==R,就一个球,它最后爆炸,也就是当前必须打if (L == R) return nums[L - 1] * nums[L] * nums[R + 1];//只调用i,左右没有炸//然后如果还有更多的元素,那分几种情况//1)L最后爆炸--先打爆右边部分的最大分数+int max = f(nums, L + 1, R) + nums[L - 1] * nums[L] * nums[R + 1];//最后打爆L的分数//2)R最后爆炸--先打爆左边部分的分数+最后打爆R的分数max = Math.max(max, f(nums, L, R - 1) + nums[L - 1] * nums[R] * nums[R + 1]);//3)L+1,R-1中的某个位置i最后爆炸//三者取最大值//情况3就得枚举了,先打爆i左边的位置,再打爆右边的位置,最后加打爆i的得分for (int i = L + 1; i < R; i++) {max = Math.max(max, f(nums, L, i - 1) + f(nums, i + 1, R) + nums[L - 1] * nums[i] * nums[R + 1]);}return max;}//主函数,调整arrpublic static int maxValueShootingBall(int[] nums){if (nums == null || nums.length == 0) return 0;int N = nums.length;int[] help = new int[N + 2];help[0] = 1;help[N + 1] = 1;for (int i = 0; i < N; i++) {help[i + 1] = nums[i];}return f(help, 1, N);//0和N+1全是1,永远不会爆炸}

既然是范围上的尝试,填表就非常固定了,dp[i][j]代表:打爆i–j范围上的气球,能得到的最大分数是多少?
我们要的结果就是dp[1][N]

i和j都是0–N+1长度
故填表为N+2平方的表,L<=R,这种填表模式都是固定的
(1)先填主对角线,i=j,就剩一个气球了,dp[i][i]=[i-1][i][i+1];
(2)再填副对角线,j=i+1,俩气球,后打爆i【那就呀先打爆i+1=j】,或者后打爆j【那就要先打爆i】,2者取最大值:dp[i][i]=max(dp[i + 1][i + 1]+[i-1][i][j+1], dp[i][i][i-1][j][j+1] );——第一项:因为你先打爆i+1–i+1范围,即气球j,第二项,因为你先打爆i–i范围,就气球i;
(3)再填任意位置dp[i][i],暴力递归怎么填,dp[i][i]就怎么填!

这种填表的模式非常固定的,一点都不麻烦,关键在于暴力递归的代码怎么写,理解清楚之后,这个表也就很容易搞定了。

//改DP,范围的尝试,常规套路填表是固定的格式public static int maxValueShootingBallDP(int[] nums){if (nums == null || nums.length == 0) return 0;int N = nums.length;int[] help = new int[N + 2];help[0] = 1;help[N + 1] = 1;for (int i = 0; i < N; i++) {help[i + 1] = nums[i];}//下面都是处理help,根据N来收拾int[][] dp = new int[N+2][N+2];//主对角for (int i = 1; i <= N; i++) {dp[i][i] = help[i - 1] * help[i] * help[i + 1];}//副对角--i后爆炸,或者i+1后爆炸for (int i = 1; i < N; i++) {dp[i][i + 1] = Math.max(dp[i + 1][i + 1] + help[i - 1] * help[i] * help[i + 2],dp[i][i] + help[i - 1] * help[i + 1] * help[i + 2]);}//任意位置,看递归for (int i = N - 2; i >= 1 ; i--) {for (int j = i + 2; j <= N; j++) {int max = dp[i + 1][j] + help[i - 1] * help[i] * help[j + 1];//最后打爆i的分数//2)j最后爆炸--先打爆左边部分的分数+最后打爆j的分数max = Math.max(max, dp[i][j - 1] + help[i - 1] * help[j] * help[j + 1]);//3)L+1,R-1中的某个位置i最后爆炸//三者取最大值//情况3就得枚举了,先打爆i左边的位置,再打爆右边的位置,最后加打爆i的得分for (int k = i + 1; k < j; k++) {max = Math.max(max, dp[i][k - 1] + dp[k + 1][j] + help[i - 1] * help[k] * help[j + 1]);}dp[i][j] = max;}}return dp[1][N];}

测试代码:

public static void test(){int[] nums = {3,2,5};System.out.println(maxValueShootingBall(nums));System.out.println(maxValueShootingBallDP(nums));}public static void main(String[] args) {test();}

总结

提示:重要经验:

1)L–R范围上的尝试,往往都是讨论L和R位置处怎么操作,当然也不排除这种枚举素有位置的情况,另外,先处理L还是后处理L,看题决定;这里就是后打爆L
2)L–R范围上的尝试,填表非常固定的模式,很容易,摸清楚暴力递归的代码,这个表很容易就填好了。

打爆一排气球arr,你能获得的最大分数是多少?相关推荐

  1. 【BZOJ-4631】踩气球 线段树 + STL

    4631: 踩气球 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 224  Solved: 114 [Submit][Status][Discuss ...

  2. 【LeetCode笔记】312. 戳气球(Java、动态规划)

    文章目录 题目描述 思路 && 代码 二刷 题目描述 一眼动态规划,但思路确实不好想 面试被问过,直接人没了= = 思路 && 代码 核心思路:关心[最后一个被爆的气球 ...

  3. bzoj 4631: 踩气球(线段树)

    4631: 踩气球 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 375  Solved: 189 [Submit][Status][Discuss ...

  4. LeetCode 312. 戳气球(Java)

    题目 有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中. 现在要求你戳破所有的气球.戳破第 i 个气球,你可以获得 nums[i - 1] * num ...

  5. 【bzoj4631】踩气球

    4631: 踩气球 Time Limit: 10 Sec   Memory Limit: 256 MB Submit: 372   Solved: 186 [ Submit][ Status][ Di ...

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

    一.大气球的最大得分 1.对应letecode链接 打气球的最大分数_牛客题霸_牛客网 (nowcoder.com) 2.题目描述: 3.解题思路 本题个人觉得本题巨难:主要步骤如下: 1.预处理:为 ...

  7. 312. 戳气球(区间dp)

    链接:https://leetcode-cn.com/problems/burst-balloons/ 首先这个长度为500的范围可以猜测出是O(n^3)区间dp 这里主要讲述为什么状态定义要定义成开 ...

  8. 【LeetCode】312. 戳气球

    312. 戳气球(困难) 解法一:动态规划 首先看一个区间: 区间(i,j) 是一个开区间,因为我们只能戳爆 i 和 j 之间的气球,不能戳爆索引为 i 和 j 的气球. 我们不妨考虑该区间内被戳爆的 ...

  9. LeetCode·312.戳气球·动态规划

    312.戳气球 题目 示例 思路 首先必须要说明,这个题目的状态转移方程真的比较巧妙,所以说如果你看了题目之后完全没有思路恰恰是正常的.虽然最优答案不容易想出来,但基本的思路分析是我们应该力求做到的. ...

  10. Java实现 LeetCode 452 用最少数量的箭引爆气球

    452. 用最少数量的箭引爆气球 在二维空间中有许多球形的气球.对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标.由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够 ...

最新文章

  1. linux last 命令年份,【帝联运维课堂】(第七十二期)Linux下last命令如何显示年份...
  2. k8s argo workflow获取登录token的命令
  3. Increasing Subsequence (hard version)
  4. php workman 多线程,workerman如何多线程
  5. Anaconda中软件库更新
  6. html制作花样链接卡页面_8 个「新标签页」Chrome 扩展,把 New Tab 页面玩出花样 | Matrix 精选...
  7. MogoH5+基于Hbuilder做ios真机测试
  8. linux下ftp服务和dns的关系,linux企业常用服务---dns+ftp+dhcp
  9. 人才稀缺的区块链,程序员转型入门必看这四项技能
  10. Apache Dubbo集群容错
  11. 【数字信号处理】基于matlab数字信号同步压缩变换【含Matlab源码 1534期】
  12. Tecplot读取Excel文件中的数据
  13. 分布式自增序列id的实现(二) ---分布式序号生成器---基于Redis的自增功能
  14. 【Angular】@Input和@Output
  15. java使用阿里云发送通知短信
  16. 低成本撬动TK亿万流量 TK带货视频有多简单?
  17. ssm中报错: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type a
  18. mysql报“ASCII\0appearedinthestatement“
  19. CSDN这个家比博客园温馨好多啊,我要搬家了。。。
  20. matplotlib从折线图入门并解决中文乱码

热门文章

  1. 安装postgresql出现问题合集(Fatal errorThe pgAdmin 4 server could not be contacted:
  2. 黑桃符号java怎么打印出来_java入门基础(四)
  3. android7.1 科大讯飞语音引擎设置为首选引擎
  4. Week8 CSP模拟 T2 HRZ学英语
  5. notepad++之正则表达式的使用
  6. 神山的方向至诚地祈祷、朝拜
  7. 0w1_CTF_Writeup
  8. 魔兽世界开服架设服务器搭建教程
  9. 哈佛大学幸福课笔记一
  10. 用浏览器控制台获取一些网页资源