打爆一排气球arr,你能获得的最大分数是多少?
打爆一排气球,你能获得的最大分数是多少?
提示:题难没关系,见过一遍总比完全没见过的好,见过的话,再复习一遍,也就很快想起来了。
文章目录
- 打爆一排气球,你能获得的最大分数是多少?
- @[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,你能获得的最大分数是多少?相关推荐
- 【BZOJ-4631】踩气球 线段树 + STL
4631: 踩气球 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 224 Solved: 114 [Submit][Status][Discuss ...
- 【LeetCode笔记】312. 戳气球(Java、动态规划)
文章目录 题目描述 思路 && 代码 二刷 题目描述 一眼动态规划,但思路确实不好想 面试被问过,直接人没了= = 思路 && 代码 核心思路:关心[最后一个被爆的气球 ...
- bzoj 4631: 踩气球(线段树)
4631: 踩气球 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 375 Solved: 189 [Submit][Status][Discuss ...
- LeetCode 312. 戳气球(Java)
题目 有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中. 现在要求你戳破所有的气球.戳破第 i 个气球,你可以获得 nums[i - 1] * num ...
- 【bzoj4631】踩气球
4631: 踩气球 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 372 Solved: 186 [ Submit][ Status][ Di ...
- 戳气球和布尔运算问题(巨难)
一.大气球的最大得分 1.对应letecode链接 打气球的最大分数_牛客题霸_牛客网 (nowcoder.com) 2.题目描述: 3.解题思路 本题个人觉得本题巨难:主要步骤如下: 1.预处理:为 ...
- 312. 戳气球(区间dp)
链接:https://leetcode-cn.com/problems/burst-balloons/ 首先这个长度为500的范围可以猜测出是O(n^3)区间dp 这里主要讲述为什么状态定义要定义成开 ...
- 【LeetCode】312. 戳气球
312. 戳气球(困难) 解法一:动态规划 首先看一个区间: 区间(i,j) 是一个开区间,因为我们只能戳爆 i 和 j 之间的气球,不能戳爆索引为 i 和 j 的气球. 我们不妨考虑该区间内被戳爆的 ...
- LeetCode·312.戳气球·动态规划
312.戳气球 题目 示例 思路 首先必须要说明,这个题目的状态转移方程真的比较巧妙,所以说如果你看了题目之后完全没有思路恰恰是正常的.虽然最优答案不容易想出来,但基本的思路分析是我们应该力求做到的. ...
- Java实现 LeetCode 452 用最少数量的箭引爆气球
452. 用最少数量的箭引爆气球 在二维空间中有许多球形的气球.对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标.由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够 ...
最新文章
- linux last 命令年份,【帝联运维课堂】(第七十二期)Linux下last命令如何显示年份...
- k8s argo workflow获取登录token的命令
- Increasing Subsequence (hard version)
- php workman 多线程,workerman如何多线程
- Anaconda中软件库更新
- html制作花样链接卡页面_8 个「新标签页」Chrome 扩展,把 New Tab 页面玩出花样 | Matrix 精选...
- MogoH5+基于Hbuilder做ios真机测试
- linux下ftp服务和dns的关系,linux企业常用服务---dns+ftp+dhcp
- 人才稀缺的区块链,程序员转型入门必看这四项技能
- Apache Dubbo集群容错
- 【数字信号处理】基于matlab数字信号同步压缩变换【含Matlab源码 1534期】
- Tecplot读取Excel文件中的数据
- 分布式自增序列id的实现(二) ---分布式序号生成器---基于Redis的自增功能
- 【Angular】@Input和@Output
- java使用阿里云发送通知短信
- 低成本撬动TK亿万流量 TK带货视频有多简单?
- ssm中报错: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type a
- mysql报“ASCII\0appearedinthestatement“
- CSDN这个家比博客园温馨好多啊,我要搬家了。。。
- matplotlib从折线图入门并解决中文乱码
热门文章
- 安装postgresql出现问题合集(Fatal errorThe pgAdmin 4 server could not be contacted:
- 黑桃符号java怎么打印出来_java入门基础(四)
- android7.1 科大讯飞语音引擎设置为首选引擎
- Week8 CSP模拟 T2 HRZ学英语
- notepad++之正则表达式的使用
- 神山的方向至诚地祈祷、朝拜
- 0w1_CTF_Writeup
- 魔兽世界开服架设服务器搭建教程
- 哈佛大学幸福课笔记一
- 用浏览器控制台获取一些网页资源