Sorting ensures that events are processed in left-to-right order. If two events occur at the same x-coordinate, “start” events are processed before “end” events to handle overlaps correctly and prioritize taller buildings.
Key takeaways:
The Skyline Problem involves drawing the outline of buildings on a 2D plane based on their positions and heights. The goal is to find the shape of the skyline when viewed from a distance.
The Skyline Problem has applications in computer graphics and urban planning.
It combines sorting, heap-based data structures, and event-driven computation, showcasing algorithm design and optimization.
This problem is commonly asked in technical interviews as it tests problem-solving skills, understanding of data structures, and algorithmic efficiency.
The Skyline Problem is a popular computer science interview question. It involves drawing an outline of several buildings in a 2D plane. This problem provides an excellent opportunity to explore and apply various programming concepts, such as sorting, divide and conquer, and data structures.
Imagine standing at a distance, viewing the skyline of a city. The skyline is the shape formed by all the buildings in the city when viewed together. Your task is to determine the shape of this skyline, given all the buildings’ position and height. Each building is represented by three values in the array buildings
, where
All buildings are rectangles that sit on flat ground (height
Note: The output skyline should not have multiple horizontal lines at the same height in a row. For example, an output like
is incorrect. The three lines with height should be combined into one, so the correct version would be .
The Skyline Problem aims to represent the outline of a set of rectangular buildings when viewed from a distance. This is achieved by identifying key points where the height of the silhouette changes. To solve this problem efficiently, an optimized
Here are the detailed steps of the algorithm:
Start by creating a list of [left, right, height]
:
Add a “start” event (left, -height)
to indicate the start of the building.
Add an “end” event (right, height)
to indicate the end of the building.
The negative height in “start” events ensures taller buildings are processed first when sorting, preventing incorrect skyline calculations. It also ensures “start” events are handled before “end” events at the same x-coordinate, maintaining correct height transitions.
Sort the critical points by x-coordinate. If two points have the same x-coordinate, prioritize “start” events (negative height) over “end” events (positive height) to handle overlaps correctly.
Next, initialize the following data structures:
A max_heap
as an empty list to track active building heights.
A dictionary active_heights
to store counts of building heights, ensuring efficient pruning.
When a building’s endpoint is reached, its height remains in the max_heap
until explicitly removed. To ensure the max_heap
reflects only active buildings, we prune heights that no longer correspond to valid buildings.
A variable prev_max_height
set to 0.
An empty list result
to store the key points of the skyline.
Process each critical point (x, height)
in the sorted list:
If height < 0
(start event), add the building height to active_heights
and push its negative to max_heap
.
Otherwise, decrement active_heights
or remove the corresponding height in active_heights
if active_heights = 0
.
While max_heap
is not empty, and the tallest building in max_heap
is no longer active (not in active_heights
), remove it from the max heap.
Compute the current maximum height as -max_heap[0]
if the heap is not empty, or 0 if it is.
If the current maximum height differs from prev_max_height
, record the change by appending [x, current_max_height]
to result
and update prev_max_height
.
Return result
as the list of key points defining the skyline.
Let’s look at the following illustration to get a better understanding of the solution:
Let’s look at the example code for the approach discussed above:
from heapq import heappush, heappopfrom collections import defaultdictdef get_skyline(buildings):# Create critical pointscritical_points = []for left, right, height in buildings:critical_points.append((left, -height)) # Start of a buildingcritical_points.append((right, height)) # End of a building# Sort critical pointscritical_points.sort(key=lambda x: (x[0], x[1]))# Data structuresmax_heap = []active_heights = defaultdict(int)prev_max_height = 0result = []# Process each critical pointfor x, height in critical_points:if height < 0: # Start of a buildingheappush(max_heap, height)active_heights[-height] += 1else: # End of a buildingactive_heights[height] -= 1if active_heights[height] == 0:del active_heights[height]# Clean up the heapwhile max_heap and -max_heap[0] not in active_heights:heappop(max_heap)# Determine the current max heightcurrent_max_height = -max_heap[0] if max_heap else 0# Check if the height has changedif current_max_height != prev_max_height:result.append([x, current_max_height])prev_max_height = current_max_heightreturn resultdef main():buildings = [[[1, 7, 9], [3, 8, 8], [5, 9, 7]],[[1, 5, 10]],[[1, 2, 3], [4, 5, 6], [7, 8, 9]],[[1, 2, 5], [2, 3, 8]],[[0, 2, 10], [1, 2, 10], [2, 3, 10]],[[1000, 2000, 50], [1500, 2500, 80], [3000, 4000, 60]]]for i, building in enumerate(buildings, 1):print(f"{i}. \tBuildings =", building)print("\tSkyline =", get_skyline(building))print("-" * 100)if __name__ == "__main__":main()
Time complexity:
The overall time complexity of the solution is
The algorithm sorts all critical points. Since there are
Sorting takes
Each event is processed once, and for each event:
Adding or removing an element in the max-heap takes
Cleaning the heap involves checking the top of the heap and removing inactive elements, which can also take
The total number of operations related to the heap is proportional to the number of events,
Space complexity:
The overall space complexity of the solution is
Storing
The max-heap stores at most
The dictionary stores counts of building heights, also requiring
To learn more about data structures and algorithms and practice more LeetCode-based problems such as The Skyline Problem, look at the following list of curated courses at Educative:
If you wish to implement your solution in C++, then take a look at the “The Skyline Problem” available on the Grokking Coding Interview Patterns in C++ course.
Haven’t found what you were looking for? Contact Us
Free Resources