用最少数量的箭引爆气球[中等]

优质博文:IT-BLOG-CN

一、题目

有一些球形气球贴在一堵用XY平面表示的墙面上。墙面上的气球记录在整数数组points,其中points[i] = [xstart, xend]表示水平直径在xstartxend之间的气球。你不知道气球的确切y坐标。一支弓箭可以沿着x轴从不同点完全垂直地射出。在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为xstart,xend,且满足xstart ≤ x ≤ xend,则该气球会被引爆 。可以射出的弓箭的数量没有限制。弓箭一旦被射出之后,可以无限地前进。

给你一个数组points,返回引爆所有气球所必须射出的最小弓箭数。

示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-x = 6处射出箭,击破气球[2,8][1,6]
-x = 11处发射箭,击破气球[10,16][7,12]

示例 2:
输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。

示例 3:
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:
-x = 2处发射箭,击破气球[1,2][2,3]
-x = 4处射出箭,击破气球[3,4][4,5]

1 <= points.length <= 105
points[i].length == 2
-231 <= xstart < xend <= 231 - 1

二、代码

排序 + 贪心: 我们首先随机地射出一支箭,再看一看是否能够调整这支箭地射出位置,使得我们可以引爆更多数目的气球。

如图1-1所示,我们随机射出一支箭,引爆了除红色气球以外的所有气球。我们称所有引爆的气球为「原本引爆的气球」,其余的气球为「原本完好的气球」。可以发现,如果我们将这支箭的射出位置稍微往右移动一点,那么我们就有机会引爆红色气球,如图1-2所示。那么我们最远可以将这支箭往右移动多远呢?我们唯一的要求就是:原本引爆的气球只要仍然被引爆就行了。这样一来,我们找出原本引爆的气球中右边界位置最靠左的那一个,将这支箭的射出位置移动到这个右边界位置,这也是最远可以往右移动到的位置:如图1-3所示,只要我们再往右移动一点点,这个气球就无法被引爆了。

为什么「原本引爆的气球仍然被引爆」是唯一的要求?别急,往下看就能看到其精妙所在。

因此,我们可以断定:一定存在一种最优(射出的箭数最小)的方法,使得每一支箭的射出位置都恰好对应着某一个气球的右边界。

这是为什么?我们考虑任意一种最优的方法,对于其中的任意一支箭,我们都通过上面描述的方法,将这支箭的位置移动到它对应的「原本引爆的气球中最靠左的右边界位置」,那么这些原本引爆的气球仍然被引爆。这样一来,所有的气球仍然都会被引爆,并且每一支箭的射出位置都恰好位于某一个气球的右边界了。

有了这样一个有用的断定,我们就可以快速得到一种最优的方法了。考虑所有气球中右边界位置最靠左的那一个,那么一定有一支箭的射出位置就是它的右边界(否则就没有箭可以将其引爆了)。当我们确定了一支箭之后,我们就可以将这支箭引爆的所有气球移除,并从剩下未被引爆的气球中,再选择右边界位置最靠左的那一个,确定下一支箭,直到所有的气球都被引爆。

我们可以写出如下的伪代码:

let points := [[x(0), y(0)], [x(1), y(1)], ... [x(n-1), y(n-1)]],表示 n 个气球
let burst := [false] * n,表示每个气球是否被引爆
let ans := 1,表示射出的箭数将 points 按照 y 值(右边界)进行升序排序while burst 中还有 falsedolet i := 最小的满足 burst[i] = false 的索引 ifor j := i to n-1 doif x(j) <= y(i) thenburst[j] := trueend ifend for
end whilereturn ans

这样的做法在最坏情况下时间复杂度是O(n^2),即这n个气球对应的区间互不重叠,while循环需要执行n次。那么我们如何继续进行优化呢?

事实上,在内层的j循环中,当我们遇到第一个不满足x(j)≤y(i)j值,就可以直接跳出循环,并且这个y(j)就是下一支箭的射出位置。为什么这样做是对的呢?我们考虑某一支箭的索引it以及它的下一支箭的索引jt​,对于索引在jt之后的任意一个可以被it引爆的气球,记索引为j0​,有:x(j0)≤y(it)由于y(it)≤y(jt)显然成立,那么x(j0)≤y(jt)也成立,也就是说:当前这支箭在索引jt​(第一个无法引爆的气球)之后所有可以引爆的气球,下一支箭也都可以引爆。因此我们就证明了其正确性,也就可以写出如下的伪代码:

let points := [[x(0), y(0)], [x(1), y(1)], ... [x(n-1), y(n-1)]],表示 n 个气球
let pos := y(0),表示当前箭的射出位置
let ans := 1,表示射出的箭数将 points 按照 y 值(右边界)进行升序排序for i := 1 to n-1 doif x(i) > pos thenans := ans + 1pos := y(i)end if
end forreturn ans

这样就可以将计算答案的时间从O(n^2)降低至O(n)

class Solution {public int findMinArrowShots(int[][] points) {if (points.length == 0) {return 0;}Arrays.sort(points, new Comparator<int[]>() {public int compare(int[] point1, int[] point2) {if (point1[1] > point2[1]) {return 1;} else if (point1[1] < point2[1]) {return -1;} else {return 0;}}});int pos = points[0][1];int ans = 1;for (int[] balloon: points) {if (balloon[0] > pos) {pos = balloon[1];++ans;}}return ans;}
}

时间复杂度: O(nlog⁡n),其中n是数组points的长度。排序的时间复杂度为O(nlog⁡n),对所有气球进行遍历并计算答案的时间复杂度为O(n),其在渐进意义下小于前者,因此可以忽略。
空间复杂度: O(log⁡n),即为排序需要使用的栈空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/186554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue-动态组件、keep-alive

vue-动态组件、keep-alive 如果我们想写一个tabbar导航栏&#xff0c;我能想到的两种方式 通过if条件判断的方式实现&#xff08;不赘述&#xff09;动态组件 接下来我们就看看动态组件如何创建&#xff0c;废话不多少直接上代码&#xff08;代码中有备注&#xff09; 首先…

Panalog 日志审计系统 前台RCE漏洞复现

0x01 产品简介 Panalog是一款日志审计系统&#xff0c;方便用户统一集中监控、管理在网的海量设备。 0x02 漏洞概述 Panalog日志审计系统 sy_query.php接口处存在远程命令执行漏洞&#xff0c;攻击者可执行任意命令&#xff0c;接管服务器权限。 0x03 复现环境 FOFA&#xf…

谭巍主任专业角度解读:疣体脱落前的症状是什么?

我们时常会发现身体各个部位长出一些赘生物&#xff0c;有些属于皮肤良性改变&#xff0c;而有些则是病毒引起的&#xff0c;称之为疣体。然而在疣体脱落之前&#xff0c;通常会出现一些症状&#xff0c;这些症状可能因人而异&#xff0c;但以下是一些常见的迹象&#xff1a; 1…

如何隐藏选择选项值并用新值替换2个选项?

要隐藏选择选项值并用新值替换2个选项&#xff0c;可以使用JavaScript来实现。 首先&#xff0c;使用JavaScript获取两个选项的值&#xff0c;然后将这两个值设置为新的值&#xff0c;最后将这两个选项的可见性设置为false&#xff0c;以隐藏它们。 例如&#xff1a; <se…

笔记61:注意力提示

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第10章&#xff1a;动手学深度学习~注意力机制 a a a a a a a a

MySQL索引使用总结

索引(index) 官方定义&#xff1a;一种提高MySQL查询效率的数据结构 优点&#xff1a;加快查询速度 缺点&#xff1a; 1.维护索引需要消耗数据库资源 2.索引需要占用磁盘空间 3.增删改的时候会影响性能 索引分类 索引和数据库表的存储引擎有关&#xff0c;不同的存储引擎&am…

springboot中如何用stream流的方式把mysql取出来的值给实体类中的多个字段赋值代码实例?

在 Spring Boot 中使用 Stream 流的方式将从 MySQL 数据库取出的值赋给实体类中的多个字段&#xff0c;你可以结合使用 JDBC&#xff08;Java Database Connectivity&#xff09;和 Stream API 来实现。以下是一个示例代码&#xff1a; import org.springframework.boot.Sprin…

AndroidStudio - 新版本 Logcat 使用详解

最近这俩天正好有时间给自己做一下减法&#xff0c;忘记是去年还是今年&#xff0c;在升级 AndroidStudio 后使用 Logcat查看日志的方式也发生了一些变化&#xff0c;虽然一直在使用&#xff0c;但每当看到之前还未关闭 Logcat 命令行工具额昂也&#xff0c;就感觉可能还存在知…

Vue+element实现点击复制功能

功能 点击按钮或指定位置后将数据复制到剪贴版,避免手动复制 核心方法是 document.execCommand("Copy"); 但是这个是需要文字被选中时才可以复制成功 所以第二个方法就是创建一个input后再自动选择内容,实现复制功能 <!DOCTYPE html> <html lang"…

Multi-head attention机制

多头&#xff1a;多个相同结构的线性变换层&#xff08;方阵&#xff09;&#xff0c;要求分别线性变换 B站教学视频参考&#xff1a;https://www.bilibili.com/video/BV1eG4y1N7Jp/?p17&spm_id_frompageDriver&vd_sourcef4c7dcac0ad5ae8189bd414a3b23020d 什么是多头…

32/64位系统下使用ATT风格汇编调用c函数

32/64位系统下使用AT&T风格汇编调用c函数 32 位操作系统使用汇编调用 c 函数演示代码编译方法gcc 编译汇编as 编译连接汇编编译连接 64 位操作系统使用汇编调用 c 函数演示代码编译方法gcc 编译汇编as 编译连接汇编编译连接 32 位操作系统使用汇编调用 c 函数 演示代码 文…

冒泡排序算法是对已知的数列进行从小到大的递增排序。

题目描述冒泡排序算法是对已知的数列进行从小到大的递增排序每个实例输出两行&#xff0c;第一行输出第1轮结果, 第二行输出最终结果 它的排序方法如下: 1.对数列从头开始扫描&#xff0c;比较两个相邻的元素,如果前者大于后者,则交换两者位置 2.重复步骤1&#xff0c;直到没有…

【Python】Python开发微信小程序

Python作为一门简单易学、功能强大的编程语言&#xff0c;具备广泛的应用领域。近年来&#xff0c;越来越多的开发者选择使用Python来开发微信小程序&#xff0c;以满足用户对于更加高质量、高性能应用的需求。 Python为什么适合开发微信小程序&#xff1f; 首先&#xff0c;…

RocketMQ源码剖析之createUniqID方法

目录 版本信息&#xff1a; 写在前面&#xff1a; 源码剖析&#xff1a; 总计&#xff1a; 版本信息&#xff1a; RocketMQ-5.1.3 源码地址&#xff1a;https://github.com/apache/rocketmq 写在前面&#xff1a; 首先&#xff0c;笔者先吐槽一下RocketMQ的官方&#xff0…

attention中Q,K,V的理解

第一种 1.首先定义三个线性变换矩阵&#xff0c;query&#xff0c;key&#xff0c;value&#xff1a; class BertSelfAttention(nn.Module):self.query nn.Linear(config.hidden_size, self.all_head_size) # 输入768&#xff0c; 输出768self.key nn.Linear(config.hidde…

11-30例题-python

50. Pow(x, n) class Solution(object):def myPow(self, x, n):""":type x: float:type n: int:rtype: float"""# 终止条件if n0:return 1# 三种情况# n<0 n的-x分之一if n<0:x1/xn-n# x是奇数 x*x的偶数次方if n%2:return x *self.myPow…

上海线下活动 | LLM 时代的 AI 编译器实践与创新

今年 3 月份&#xff0c; 2023 Meet TVM 系列首次线下活动从上海出发&#xff0c;跨越多个城市&#xff0c;致力于为各地关注 AI 编译器的工程师提供一个学习、交流的平台。 12 月 16 日 2023 Meet TVM 年终聚会将重返上海&#xff0c;这一次我们不仅邀请了 4 位资深的 AI 编…

自动伸缩:解密HPA、VPA、CA和CPA智能调整应用大小和数量

关注【云原生百宝箱】公众号&#xff0c;快速掌握云原生 Kubernetes提供了多种自动伸缩机制&#xff0c;例如HPA&#xff08;Horizontal Pod Autoscaling&#xff09;&#xff0c;可以根据不同情况动态调整Pod副本数量。此功能使 Pod 能够有效地处理当前流量&#xff0c;而无需…

pytorch中的激活函数详解

1 激活函数介绍 1.1 什么是激活函数 激活函数是神经网络中引入的非线性函数&#xff0c;用于捕获数据中的复杂关系。它来自动物界的灵感&#xff0c;动物的神经元会接受来自对它有作用的其他神经元的信号&#xff0c;当然这些信号对该神经元的作用大小不同&#xff08;即具有不…

Jmeter+ant+jenkins实现持续集成看这一篇就搞定了!

jmeterantjenkins持续集成 一、下载并配置jmeter 首先下载jmeter工具&#xff0c;并配置好环境变量&#xff1b;参考&#xff1a;https://www.cnblogs.com/YouJeffrey/p/16029894.html jmeter默认保存的是.jtl格式的文件&#xff0c;要设置一下bin/jmeter.properties,文件内容…