218 天際線問題

王培琳發表於2020-11-14

題目描述:
城市的天際線是從遠處觀看該城市中所有建築物形成的輪廓的外部輪廓。現在,假設您獲得了城市風光照片(圖A)上顯示的所有建築物的位置和高度,請編寫一個程式以輸出由這些建築物形成的天際線(圖B)。
在這裡插入圖片描述
每個建築物的幾何資訊用三元組 [Li,Ri,Hi] 表示,其中 Li 和 Ri 分別是第 i 座建築物左右邊緣的 x 座標,Hi 是其高度。可以保證 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX 和 Ri - Li > 0。您可以假設所有建築物都是在絕對平坦且高度為 0 的表面上的完美矩形。

例如,圖A中所有建築物的尺寸記錄為:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] 。

輸出是以 [ [x1,y1], [x2, y2], [x3, y3], … ] 格式的“關鍵點”(圖B中的紅點)的列表,它們唯一地定義了天際線。關鍵點是水平線段的左端點。請注意,最右側建築物的最後一個關鍵點僅用於標記天際線的終點,並始終為零高度。此外,任何兩個相鄰建築物之間的地面都應被視為天際線輪廓的一部分。

例如,圖B中的天際線應該表示為:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]。

說明:

任何輸入列表中的建築物數量保證在 [0, 10000] 範圍內。
輸入列表已經按左 x 座標 Li 進行升序排列。
輸出列表必須按 x 位排序。
輸出天際線中不得有連續的相同高度的水平線。例如 […[2 3], [4 5], [7 5], [11 5], [12 7]…] 是不正確的答案;三條高度為 5 的線應該在最終輸出中合併為一個:[…[2 3], [4 5], [12 7], …]

方法1:
主要思路:
(1)先使用multiset<pair<int,int>> points 來統計所有的建築的左右兩個頂點,並把左邊的頂點的高度置為負數,便於區分(同一建築的左右點)和排序(兩個建築,右邊建築的左頂點和左邊建築的右頂點相同時),這樣將所有的頂點存入到multiset中,同時進行了排序;
(2)從頭掃描multiset,使用輔助陣列heights來統計當前正在統計的範圍內的各個建築的高度,掃描過程中,若當前高度數負數,則將高度插入到heights,若是正數,則從heights中刪除該高度(注意,為了只刪除重複高度中的一個,需要先使用find函式找出該高度對應的一個迭代器,來實現刪除一個重複的高度的目的),同時使用pre_max_height來統計之前出現過的最大高度;
(3)當新的最大的高度和之前的最大的高度不一致時,說明此時是一個關鍵點,將該關鍵點插入到結果中,並更新最高點;

class Solution {
public:
    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
        multiset<pair<int,int>> points;//統計每個建築的左右頂點
        for(vector<int>& b:buildings){
            points.insert({b[0],-b[2]});//左頂點的高度使用對應的負數進行表示
            points.insert({b[1],b[2]});//右頂點的高度正常表示
        }
        vector<vector<int>>res;//儲存結果
        int pre_max_height=0;//儲存之前出現過的最高高度
        multiset<int> heights({0});//儲存有效的建築的高度,既相當於建築的左頂點出現時,將高度壓入到該陣列中,建築的右頂點出現時,減該高度從陣列中刪除
        for(auto& point:points){//遍歷所有的建築的左右頂點,這裡已經自動進行了排序
        	//決定當前建築剛出現(既建築的左頂點出現,將對應的高度插入到高度陣列中),還是建築即將跳過(既建築的右頂點出現,將對應的高度從高度陣列中刪除)
            if(point.second>0){
                heights.erase(heights.find(point.second));
            }
            else{
                heights.insert(-point.second);
            }
            int cur_max_height=*heights.rbegin();//獲得當前的高度陣列中的最大的高度
            if(pre_max_height!=cur_max_height){//判斷當前的最大的高度和之前的最大的高度是否是同一個高度,決定是否是新的關鍵點
                pre_max_height=cur_max_height;
                res.push_back({point.first,pre_max_height});//關鍵點使用當前點的橫座標和當前的最大的高度組成
            }
        }
        return res;
    }
};

相關文章