[每日一题]452. Minimum Number of Arrows to Burst Balloons

题目描述

本周主题:贪心算法算法

本题难度:Mediumide

作题日期:2017年3月28日学习

本题地址: leetcode.com/problems/mi…spa

There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter and hence the x-coordinates of start and end of the diameter suffice. Start is always smaller than end. There will be at most 104 balloons.3d

An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be shot to burst all balloons.code

Example:cdn

Input:[[10,16], [2,8], [1,6], [7,12]]
Output:2
Explanation:One way is to shoot one arrow for example
at x = 6 (bursting the balloons [2,8] and [1,6])
and another arrow at x = 11
(bursting the other two balloons).blog

题目分析

题目大意是沿水平直线放 n 个热气球,其大小可用区间(x,y) 表示,热气球能够重叠,而后从 正上方(垂直方向)放箭可刺破气球。问可用最少多少支箭可刺破全部的气球。排序

抽象

根据题意,咱们能够抽象成以下的数学问题:给定 n 个区间,求其一共有多少个相交的部分。递归

旁白:只要咱们朝相交区间的任意一点射箭,就能用最少的箭刺破全部的气球。

举个例子:假设有两个气球,其区间范围分别在 [1, 5]、[3, 8] ,那么朝区间[3, 5] 中的任意一点射一支箭就能够刺破两只气球。

这个问题的难点在于:1,输入的 n 个区间都是无序的;2,须要处理 n 个区间。

算法的本质在于下降须要处理的问题的规模。好比动态规划的关键是 求 n 与 1 到 n - 1的关系;递归是须要咱们找出 n 与 n - 1 的关系;二分法是一次将搜索空间折半;分治算法要求咱们将复杂的分词分解成独立的子问题... ...

旁白:这是个人浅显认识,若有不一样的意见,欢迎留言讨论。

根据咱们分析出的难点,咱们能够分两个方面解决该问题。

  1. 输入的区间无序:经过排序,将无序的区间从新组合成有序的区间。
  2. 须要处理 n 个区间:经过合并的方法,将两个区间合并成一个区间。这样能够将 n 的问题转换成求 2 个区间合并的问题。

2个区间的三种状态

第一种状态:区间嵌套



图一

如图一所示,区间 [0, 13] 和 [2, 5] 合并后,区间大小变成了 [0, 5] 。

旁白:为何是 [0, 5] ?
实际上,在当前的步骤,咱们须要记录两个重要的值: ans 和 terminal 。
ans 表示当前最多须要多少根箭;terminal 表示当前的全部区间的最右边的点。

每次合并的本质是肯定 ans 和 terminal 的值,[0, 5] 区间的 5 表示的就是 terminal 的值。

旁白:为何我要用 terminal 而不是 end ?
由于在 某些语言中, end 是一个关键词。

第二种状态:区间相交



图二

如图二所示,区间[0,8] 和 [2, 15] 合并后,区间大小变成了[0, 8], terminal 的值是 8。

第三种状态:区间不相交



图三

如图三所示,区间[0,8] 和 [9, 15] 合并后, terminal 的值是 15。

解题方案

根据“题目分析”中的2个区间的三种状态,咱们能够用:

  1. 变量 ans 来保存当前至少须要的射箭数量
    当相邻两个区间不重合的时候,须要加 1
  2. 变量 terminal 来保存当前箭所能射的最右的值
    下一个区间的 start 的值大于 terminal,那么 ans 必定要加 1, 也就是要多射一次箭
    下一个区间的 start 小于 terminal, 那么 ans 的值不须要变

旁白:terminal 的名词太难定义了!其实能够这么理解,terminal 表示的当前这支箭可射区域的最大值。好比在两个相交的区间里,咱们举的第一个例子,[1, 5]、[3, 8] 的重叠区间是 [ 3, 5] ,这说明了在区间 [3,5] 任意一点射箭都是能够的,只是不能过 5 这个点。terminal 就是表示的可射区域的最大值:5。

若是你有更好的解释,麻烦留言评论。谢谢~

具体请参考以下的分析



图四
ans 的值没有变化;terminal 变的更小了。


图五
ans 的值没有变化;terminal 的值也没有变化。


图六
ans 的值没有变化;terminal 变的更大了。

start 升序排列



图七

若是按照 start 升序排列,须要三种状况下 ans 和 terminal 的变化。

end 升序排列



图八

旁白:为何只须要考虑不相交的状况?
由于end升序排列,不可能出现嵌套的状况,相交的状况又不要想 ans 和 terminal 的值。

最佳提交

补充说明


@逍遥居人 的提交详细的说明贪心算法的关键点(重叠的points越多越好),他代码的思路也跟文中描述的有点不同,他是从最后一个区间开始往回找。


@kun 的代码有很是详细的算法解释,很是的赞!

关于咱们

每日一道算法题是由全球3000位小伙伴组成的一个纯粹的算法学习社区:经过天天一块儿作一道算法题来提高咱们的算法能力。

长按下面的二维码,关注每日一道算法题公众号,跟咱们一块儿学习算法!

相关文章
相关标签/搜索