用最少数量的箭引爆气球

力扣题目链接(opens new window)

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。

一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。

示例 1:

  • 输入:points = [[10,16],[2,8],[1,6],[7,12]]
  • 输出:2
  • 解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球

示例 2:

  • 输入:points = [[1,2],[3,4],[5,6],[7,8]]
  • 输出:4

示例 3:

  • 输入:points = [[1,2],[2,3],[3,4],[4,5]]
  • 输出:2

示例 4:

  • 输入:points = [[1,2]]
  • 输出:1

示例 5:

  • 输入:points = [[2,3],[2,3]]
  • 输出:1

提示:

  • 0 <= points.length <= 10^4
  • points[i].length == 2
  • -2^31 <= xstart < xend <= 2^31 - 1

思路

题意理解

题干描述套了一个“打气球”作为背景,搞得有点抽象,其实就是给一个二维数组,寻找里面子数组的重合区间的一个问题

题意图解如下:

  • 输入:points = [[1,2],[3,6],[4,8],[7,12],[10,16]]
  • 输出:3

如图所示,[1,2]和[3,6]两个区间所代表的的“气球”没有重合,因此不能同时打爆

而[3,6]和[4,8]位置的两个“气球”是有重合的,因此可以使用一支箭同时打爆

同理[7,12]和[10,16]位置也可以消耗一支箭打爆两个气球,因此要打爆所有气球,最少使用的箭数是3

你可能会想:那为什么不能同时打爆[4,8]和[7,12]位置的气球呢?

如果是上面这种打法,那不重叠的[3,6]和[10,16]区间又分别需要消耗两支箭,导致整体使用箭数不是最少

因此同时打爆[4,8]和[7,12]位置的气球不是最优解

由上述讨论可以得出贪心思路:

局部最优:让重叠区间尽可能多的在一块,好一次打完

全局最优:使用最少的箭打完所有气球

本题难点有两个:

1、如何模拟射气球的过程

2、如何记录重叠数组

过程模拟

模拟射气球时,不需要真的去删除被射中的气球数组,只需计数即可

还是以上面的图为例

先将所有气球按照左边界排序

情况1:不重叠,需要额外使用箭

以[1,2]和[3,6]为例,[3,6]的左边界3大于[1,2]的右边界2,因此这两个区间无重叠,需要两支箭分别射击,即:

if(points[i][0] > points[i - 1][1]){//左边界3大于右边界2
res++;//使用弓箭数增加
}
情况2:重叠检查并更新右边界

以[3,6]和[4,8]为例,显然这两个位置的气球时重叠的,那肯定就不满足情况1的条件,因此我们可以接着情况1写在else里面

if(points[i][0] > points[i - 1][1]){//左边界3大于右边界2
res++;//使用弓箭数增加
}else{//(points[i][0] <= points[i - 1][1]的情况 }

为什么有等于?因为题目说了挨着的气球也可以一次打爆

当气球有重合时,我们不需要使用新的弓箭。但是如果遍历到下一个区间,它也与之前的区间有重合,我们怎么去处理这种情况?

这个时候就需要在遇到重叠区间时,记录当前最小的右边界以提供给下一个区间进行重叠判断

如图所示,当下标i遍历到[4,8]区间时,其与下标为i - 1的[3,6]区间有重合

此时不知道之后会不会还有区间与这两个区间有重合,所以需要记录下这两个区间中最小的那个右边界用于后续判断

最小右边界显然是6,当下标i遍历到[7,12]时,[7,12]的左边界大于当前的最小右边界6

所以[7,12]没有与[3,6]、[4,8]有重叠部分,因此需要额外的弓箭来射击(满足情况1)

所以情况2的代码逻辑如下:

if(points[i][0] > points[i - 1][1]){//左边界3大于右边界2
res++;//使用弓箭数增加
}else{//(points[i][0] <= points[i - 1][1]的情况
points[i][1] = min(points[i - 1][1], points[i][1]);//取两个重合区间中最小的右边界作为当前右边界
}

代码

根据上述分析可以总结出以下步骤:

1、自定义比较规则cmp,按左边界对数组先进行排序

2、判断数组为0的情况

2、初始化弓箭数量变量(注意初始值为1,因为0的情况已经判断过,所以之后的情况至少需要一支弓箭)

3、遍历数组,判断两种情况

  • 情况1,无重叠,更新res值记录所需的新弓箭
  • 情况2,有重叠,更新最小右边界,即(points[i] [0] <= points[i - 1] [1]
class Solution {
public:
static bool cmp(const vector<int>& a, const vector<int>& b){
return a[0] < b[0];
}
int findMinArrowShots(vector<vector<int>>& points) {
if (points.size() == 0) return 0;//先判断数组为0的情况
//对二维数组进行排序
sort(points.begin(), points.end(),cmp);
int res = 1;//记录弓箭使用数量,因为0的情况已经判断过,所以之后的情况至少需要一支弓箭
//遍历数组
for(int i = 1; i < points.size(); ++i){//从1开始,不然比到最后会有负数
//判断左右边界情况,即重叠情况
if(points[i][0] > points[i - 1][1]){//情况1,无重叠
res++;
}else{//情况2,有重叠,更新最小右边界//(points[i][0] <= points[i - 1][1]
points[i][1] = min(points[i - 1][1], points[i][1]);
}
}
return res;
}
};

【LeetCode贪心#09】用最少数量的箭引爆气球(涉及区间重叠情况判断)的更多相关文章

  1. Leetcode 452.用最少数量的箭引爆气球

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

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

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

  3. [LeetCode] Minimum Number of Arrows to Burst Balloons 最少数量的箭引爆气球

    There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided ...

  4. [Swift]LeetCode452. 用最少数量的箭引爆气球 | Minimum Number of Arrows to Burst Balloons

    There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided ...

  5. 452 Minimum Number of Arrows to Burst Balloons 用最少数量的箭引爆气球

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

  6. LeetCode:用最少的箭引爆气球【452】

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

  7. Gas Station|leetcode 贪心

    贪心:尽量将gas[i]-cost[i]>0的放在前面,gas[i]-cost[i]<0的放在后面.(路程的前面有汽油剩下,耗汽油的放在路程的后面). 能否全程通过的 条件 是:sum(g ...

  8. LEETCODE 07 09

    最近忙着面试耽误了几天,今天刷了07,09都是字符串处理,一个是大数反转,一个是回文数判断,我都是转成字符串处理的,过了是过了,但是挺慢的,先记着,等有机会优化下 题目 给定一个 32 位有符号整数, ...

  9. leetcode: 贪心

    1. jump game Given an array of non-negative integers, you are initially positioned at the first inde ...

  10. Leetcode 贪心 Best Time to Buy and Sell Stock

    本文为senlie原创.转载请保留此地址:http://blog.csdn.net/zhengsenlie Best Time to Buy and Sell Stock Total Accepted ...

随机推荐

  1. 保护IIS Web服务器安全的技巧

    首先,开发一套安全策略 保护Web服务器的第一步是确保网络管理员清楚安全策略中的每一项制度.如果公司高层没有把服务器的安全看作是必须被保护的资产,那么保护工作是完全没有意义的.这项工作需要长期的努力. ...

  2. git和coding的使用

    1.注册 coding ::::::https://coding.net/ 2.个人设置中添加上邮箱账号和密码 3.下载git 4.在coding中新建项目,并对项目初始化---生成分支,会生成url ...

  3. Linux(CentOS7)中安装Docker

    Linux(CentOS7)中安装Docker 什么是Docker? Docker是一个开源项目, 诞生于2013年初,最初是dotCloud公司内部的一个业余项目.它基于Google公司推出的Go语 ...

  4. 操作系统|02.Linux基础(1)

    Linux基础 1.Linux系统安装.密码的破解 1.1常见的系统 unix:性能稳定,价格高昂,命令与Linux相通.多为大型政府单位.大型企业.金融机构使用. Linux:开源.自由 Linux ...

  5. 微信支付 easy wechat 使用

    /*微信小程序的配置信息微信商户信息*/ public function __construct(){ parent::__construct(); $this->OrderModel = ne ...

  6. 关闭Google自动更新

    一.禁用任务计划 二.禁用更新服务 三.重命名更新程序 首先找到谷歌浏览器的安装位置

  7. Python+Django(1)——建立项目

    为项目新建一个目录,将其命名为learning_log,再在终端中切换到这个目录(Python 3): 运行模块venv 来创建一个名为ll_env的虚拟环境:python -m venv ll_en ...

  8. 2020.3.9 ~ 2020.3.15 ACM训练周总结

    一.本周ACM学习相关内容 学习了dfs和bfs -- 4小时 课上系统的学习了vector等stl函数的使用即注意事项-3小时 二.题数与耗时 师哥安排了12道题,做了五道(不包含比赛题):大概4个 ...

  9. 照亮体育馆 Barisal Stadium

    UVA10641 题目为逆时针顺序编号,这里直接将数组开两倍来处理环.(然而不知为啥开到1000也能过) 定义: Corners[i]Corners[i]Corners[i]为体育馆点的坐标. Lig ...

  10. JMeter参数化(一)--CSV参数化

    一.CSV Data Set Config 1.添加配置元件-CSV Data Set Config 其中,分隔符不能是参数化的值中的符号,否则会被截断. 2.调用 3.循环读取文件中数据 假设数据内 ...