[每日一題]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位小夥伴組成的一個純粹的算法學習社區:經過天天一塊兒作一道算法題來提高咱們的算法能力。

長按下面的二維碼,關注每日一道算法題公衆號,跟咱們一塊兒學習算法!

相關文章
相關標籤/搜索