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

每日一題發表於2019-03-04

題目描述

本週主題:貪心演算法

本題難度:Medium

做題日期:2017年3月28日

本題地址: leetcode.com/problems/mi…

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.

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.

Example:

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).

題目分析

題目大意是沿水平直線放 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個區間的三種狀態

第一種狀態:區間巢狀

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

圖一

如圖一所示,區間 [0, 13] 和 [2, 5] 合併後,區間大小變成了 [0, 5] 。

旁白:為什麼是 [0, 5] ?
實際上,在當前的步驟,我們需要記錄兩個重要的值: ans 和 terminal 。
ans 表示當前最多需要多少根箭;terminal 表示當前的所有區間的最右邊的點。

每次合併的本質是確定 ans 和 terminal 的值,[0, 5] 區間的 5 表示的就是 terminal 的值。

旁白:為什麼我要用 terminal 而不是 end ?
因為在 某些語言中, end 是一個關鍵詞。

第二種狀態:區間相交

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

圖二

如圖二所示,區間[0,8] 和 [2, 15] 合併後,區間大小變成了[0, 8], terminal 的值是 8。

第三種狀態:區間不相交

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

圖三

如圖三所示,區間[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。

如果你有更好的解釋,麻煩留言評論。謝謝~

具體請參考如下的分析

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

圖四
ans 的值沒有變化;terminal 變的更小了。


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

圖五
ans 的值沒有變化;terminal 的值也沒有變化。


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

圖六
ans 的值沒有變化;terminal 變的更大了。

start 升序排列

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

圖七

如果按照 start 升序排列,需要三種情況下 ans 和 terminal 的變化。

end 升序排列

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

圖八

旁白:為什麼只需要考慮不相交的情況?
因為end升序排列,不可能出現巢狀的情況,相交的情況又不要想 ans 和 terminal 的值。

最佳提交

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

補充說明

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

@逍遙居人 的提交詳細的說明貪心演算法的關鍵點(重疊的points越多越好),他程式碼的思路也跟文中描述的有點不一樣,他是從最後一個區間開始往回找。

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

@kun 的程式碼有非常詳細的演算法解釋,非常的贊!

關於我們

每日一道演算法題是由全球3000位小夥伴組成的一個純粹的演算法學習社群:通過每天一起做一道演算法題來提升我們的演算法能力。

長按下面的二維碼,關注每日一道演算法題公眾號,跟我們一起學習演算法!

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

相關文章