LeetCode452. Minimum Number of Arrows to Burst Balloons題解

1. 題目描述

這裏寫圖片描述
【翻譯過來】:
有若干個氣球,給出了它們的直徑兩個端點的座標(X軸),我們的工作是需要用一支箭來戳破氣球。例如兩個氣球的直徑分別是(1,6)和(2,8),那麼我們就可以在x=6的座標處發射一支箭從而將它們一起戳破。求解的問題是:給出一系列氣球直徑的座標之後,最少能用多少支箭就可以戳破它們。
這裏寫圖片描述

2. 樣例

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

3. 分析

題目的意思很明確,就是利用最少的箭來戳破氣球。分析一下,我們不難得到這樣的結論:我們對所有的氣球所在的位置進行整理,如果發現兩個氣球有重疊的部分,就說明它們有可能被同一支箭戳破。
有了這樣的一個概念,接下來就是具體做法:我們將所有的氣球按照它們的直徑左端點進行升序排列,這樣我們得到的序列就有了很好的性質:後一個氣球很有可能與前一個氣球重合。
接下來,我們可以用這樣的方法:我們維護一個reference參考區間,這個區間代表的是目前爲止最小的氣球重合部分,即如果發射箭的話,射箭的座標就應該在這個reference區間裏面,如果接下來的氣球左端點都不在這個區間裏面,那麼它就不會和之前的若干個氣球一起被射中了,就要用新的箭。
即:這個貪心算法的思想就是:目前reference參考區間維護的是到目前爲止能夠被一起射中的氣球的重疊部分。
進行遍歷的時候:判斷當前氣球的左右座標與reference區間關係:

  • 如果該氣球在區間內部,說明該氣球可以和之前的氣球一起被射中,區間需要縮小至該氣球的左右端點;
  • 如果左端點在區間內部,右端點不在,說明該氣球有一部分和區間重合,所以區間需要縮小:右端點不變,左端點爲該氣球的左端點;
  • 如果左端點不在區間內部,說明該氣球與之前的氣球不能一起被射中,需要新增一支箭,之前的氣球都被戳破,reference變爲該氣球區間重新探尋;
    這裏寫圖片描述

4. 源碼

class Solution {
public:
    static bool Compare(pair<int, int>point1, pair<int, int>point2) {
        if (point1.first <= point2.first) {
            if (point1.first == point2.first) {
                return point1.second < point2.second;
            }
            return true;
        }
        return false;
    }

    int findMinArrowShots(vector<pair<int, int>>& points) {
        int counter = 1;
        sort(points.begin(), points.end(), Compare);
        pair<int, int>reference;
        if (points.size() != 0) {
            reference = points[0];
        }
        for (int i = 0; i < (int)points.size(); i++) {
            if (points[i].first <= reference.second) {
                if (points[i].second <= reference.second) {
                    reference.first = points[i].first;
                    reference.second = points[i].second;
                }
                else {
                    reference.first = points[i].first;
                }
            }
            else {
                counter++;
                reference = points[i];
            }
        }
        if (points.size() == 0) {
            return 0;
        }
        return counter;
    }
};

5. 心得

這道題,我自己設計的解法居然能夠打敗98.95%的人,有點小開心。儘管剛開始走了一點彎路:認爲只要每一個氣球與前一個氣球有重疊部分就可以一起射中,這個錯誤的思路導致了我提交了3次的Wrong Answer,因爲只與前一個氣球重疊,不代表和再之前的能夠重疊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章