【LeetCode】218. 天際線問題 結題報告 (C++)
原題地址:https://leetcode-cn.com/problems/the-skyline-problem/
題目描述:
城市的天際線是從遠處觀看該城市中所有建築物形成的輪廓的外部輪廓。現在,假設您獲得了城市風光照片(圖A)上顯示的所有建築物的位置和高度,請編寫一個程式以輸出由這些建築物形成的天際線(圖B)。
Buildings Skyline Contour
每個建築物的幾何資訊用三元組 [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], ...]
解題方案:
題目給出的提示是堆,樹狀陣列,分治演算法和線段樹。
網上的思路參考地址:https://blog.csdn.net/zycxnanwang/article/details/82989651
可以看成一個歸併問題
切分的時候,如果剩一個元素,返回它表示的兩個輪廓點,如果為空,返回空
合併是重點:
維護兩個變數:h1,h2 h1表示左半部分當前位置高度,h2表示右半部分當前位置高度
如果當前位置左半部分橫座標更小,就更新h1,從左半部分選元素;
如果當前位置右半部分橫座標更小,就更新h2,從右半部分選元素;
如果一樣大,就更新h1,h2,從左(或右)半部分選元素
當向結果中插入點時,只有和結果中最後一個點高度不同的點才能插入到結果裡
且一直使用高度max(h1,h2)。
當某一部分全部訪問完,就將另一部分直接插入結果裡(注意高度不要與之前重複)。
下面程式碼使用了multiset。mutiset:多重集合 和set最大的區別就是,它可以插入重複的元素,
如果刪除的話,相同的也一起刪除了;
如果查詢的話,返回該元素的迭代器的位置,若有相同,返回第一個元素的地址;
其他使用和set基本類似。
程式碼:
class Solution {
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
vector<pair<int, int>> h, res;
multiset<int> m;
int pre = 0, cur = 0;
for (auto &a : buildings) {
h.push_back({a[0], -a[2]});
h.push_back({a[1], a[2]});
}
sort(h.begin(), h.end());
m.insert(0);
for (auto &a : h) {
if (a.second < 0)
m.insert(-a.second);
else
m.erase(m.find(a.second));
cur = *m.rbegin();
if (cur != pre) {
res.push_back({a.first, cur});
pre = cur;
}
}
return res;
}
};