Difficulty: Hard
Topics: Heap (Priority Queue), Line Sweep, Ordered Set, Divide and Conquer
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Given the locations and heights of all the buildings, return the skyline formed by these buildings collectively.
The geometric information of each building is given in the array buildings where buildings[i] = [left_i, right_i, height_i]:
-
left_iis the x coordinate of the left edge of the$i$ -th building. -
right_iis the x coordinate of the right edge of the$i$ -th building. -
height_iis the height of the$i$ -th building.
The skyline should be represented as a list of "key points" sorted by their x-coordinate in the form [[x1,y1],[x2,y2],...]. Each key point is the left endpoint of some horizontal segment in the skyline except the last point in the list, which always has a y-coordinate
Input: buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
Output: [[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
Input: buildings = [[0,2,3],[2,5,3]]
Output: [[0,3],[5,0]]
$1 \le \text{buildings.length} \le 10^4$ $0 \le \text{left}_i < \text{right}_i \le 2^{31} - 1$ $1 \le \text{height}_i \le 2^{31} - 1$ -
buildingsis sorted byleft_iin non-decreasing order.
Every building
-
Left Edge (Start): Building enters with height
$+H$ . We encode this as(L, -H). -
Right Edge (End): Building leaves with height
$-H$ . We encode this as(R, +H).
By sorting events with std::pair<int, int>
-
Primary sort: By
$x$ -coordinate ascending. -
Tie-breaking at the same
$x$ :- Two start events: higher building (
-Hmore negative) is processed first. - Two end events: lower building (
+Hsmaller positive) is processed first. - One start and one end event: start event (
-H<+H) is processed before the end event, preventing spurious drops to height$0$ at abutting boundaries.
- Two start events: higher building (
Maintain an active height container initialized with ground level
- On start event:
activeHeights.insert(-h) - On end event:
activeHeights.erase(activeHeights.find(h)) - Whenever
$\max(\text{activeHeights}) \ne \text{prevMaxHeight}$ , a new skyline key point$[x, \max(\text{activeHeights})]$ is emitted.
-
Time Complexity:
$\mathcal{O}(N \log N)$ where$N \le 10^4$ is the number of buildings ($2N$ event sorting and$\mathcal{O}(\log N)$ multiset operations). -
Space Complexity:
$\mathcal{O}(N)$ auxiliary space to store$2N$ boundary events and the active multiset.
-
Abutting Buildings of Equal Height:
$[0, 2, 3]$ and$[2, 5, 3] \implies [[0,3], [5,0]]$ (correctly merged into a single segment). - Nested Buildings: A smaller building completely inside a taller one triggers no skyline points.
- Overlapping Starts/Ends: Handled seamlessly by signed height tie-breakers.