Given n rectangular buildings in a 2-dimensional city, compute the skyline of these buildings, eliminating hidden lines. The main task is to view buildings from a side and remove all sections that are not visible. All buildings share a common bottom and every building is represented by a triplet (left, ht, right)
'left': is the x coordinate of the left side (or wall).
'right': is x coordinate of right side
'ht': is the height of the building.
A skyline is a collection of rectangular strips. A rectangular strip is represented as a pair (left, ht) where left is x coordinate of the left side of the strip and ht is the height of the strip. I
Examples:
Input: build[][] = [[1, 5, 11 ], [2, 7, 6 ], [3, 9, 13 ], [ 12, 16, 7 ], [ 14, 25, 3 ], [ 19, 22, 18 ], [ 23, 29, 13 ], [ 24, 28, 4 ]] Output: [[1, 11 ], [ 3, 13 ], [ 9, 0 ], [ 12, 7 ], [ 16, 3 ], [ 19, 18 ], [ 22, 3 ], [ 23, 13 ], [ 29, 0 ]] Explanation: The skyline is formed based on the key-points (representing by “green” dots) eliminating hidden walls of the buildings. Note that no end point of the second building (2, 7, 6) is considered because it completely overlaps. Also, the points where the y coordinate changes are considered (Note that the top right of the third building (3, 9, 13) is not considered because it has same y coordinate.
Let us understand the problem better with the first example [[1, 5, 11 ], [2, 7, 6 ], [3, 9, 13 ], [ 12, 16, 7 ], [ 14, 25, 3 ], [ 19, 22, 18 ], [ 23, 29, 13 ], [ 24, 28, 4 ]]
One thing is obvious, we build the skyline from left to right. Now we know the point [1, 11] is going to be in the output as it is the leftmost point.
If we take a look at the right point of the first building which is [5, 11], we find that this point cannot be considered because there is a higher height building (third building in our input array [3, 9, 13[). So we ignore the right point.
Now we see the second building, its both left and right are covered. Left is covered by first building and right is covered by third building because its height is smaller than both of its neighbors. So we ignore the second building completely.
We process all the remaining building same way.
Naive Sweep Line Algorithm - O(n^2) Time and O(n) Space
Get all corner x coordinates of all buildings in an array say points[]. We are mainly going to have 2n points in this array as we have left and right for every building.
Sort the points[] to simulate the sweep line from left to right.
Now traverse through the sorted point[] and for every x point check which building has the maximum height at this point and add the maximum height to the skyline if the maximum height is different from the previously added height to the skyline.
C++
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;vector<pair<int,int>>getSkyline(vector<vector<int>>&build){vector<int>points;// Collect all left and right x-coordinates// of buildingsfor(auto&b:build){points.push_back(b[0]);points.push_back(b[1]);}// Sort all critical pointssort(points.begin(),points.end());vector<pair<int,int>>res;intprev=0;// Traverse through each point to// determine skyline heightfor(intx:points){intmaxH=0;// Check which buildings cover the // current x and get the max heightfor(auto&b:build){intl=b[0],r=b[1],h=b[2];if(l<=x&&x<r){maxH=max(maxH,h);}}// Add to result if height has changedif(res.empty()||maxH!=prev){res.push_back({x,maxH});prev=maxH;}}returnres;}intmain(){vector<vector<int>>build={{2,9,10},{3,6,15},{5,12,12}};vector<pair<int,int>>skyline=getSkyline(build);for(auto&p:skyline){cout<<"("<<p.first<<", "<<p.second<<") ";}cout<<endl;return0;}
Java
importjava.util.*;classSolution{publicList<int[]>getSkyline(int[][]build){List<Integer>points=newArrayList<>();// Collect all left and right x-coordinates// of buildingsfor(int[]b:build){points.add(b[0]);points.add(b[1]);}// Sort all critical pointsCollections.sort(points);List<int[]>res=newArrayList<>();intprev=0;// Traverse through each point to// determine skyline heightfor(intx:points){intmaxH=0;// Check which buildings cover the // current x and get the max heightfor(int[]b:build){intl=b[0],r=b[1],h=b[2];if(l<=x&&x<r){maxH=Math.max(maxH,h);}}// Add to result if height has changedif(res.isEmpty()||maxH!=prev){res.add(newint[]{x,maxH});prev=maxH;}}returnres;}publicstaticvoidmain(String[]args){int[][]build={{2,9,10},{3,6,15},{5,12,12}};Solutionsol=newSolution();List<int[]>skyline=sol.getSkyline(build);for(int[]p:skyline){System.out.print("("+p[0]+", "+p[1]+") ");}System.out.println();}}
Python
defgetSkyline(build):points=[]# Collect all left and right x-coordinates# of buildingsforbinbuild:points.append(b[0])points.append(b[1])# Sort all critical pointspoints.sort()res=[]prev=0# Traverse through each point to# determine skyline heightforxinpoints:maxH=0# Check which buildings cover the # current x and get the max heightforbinbuild:l,r,h=bifl<=x<r:maxH=max(maxH,h)# Add to result if height has changedifnotresormaxH!=prev:res.append((x,maxH))prev=maxHreturnresif__name__=='__main__':build=[[2,9,10],[3,6,15],[5,12,12]]skyline=getSkyline(build)forpinskyline:print(f'({p[0]}, {p[1]}) ',end='')print()
C#
usingSystem;usingSystem.Collections.Generic;classSolution{publicIList<int[]>GetSkyline(int[][]build){List<int>points=newList<int>();// Collect all left and right x-coordinates// of buildingsforeach(varbinbuild){points.Add(b[0]);points.Add(b[1]);}// Sort all critical pointspoints.Sort();List<int[]>res=newList<int[]>();intprev=0;// Traverse through each point to// determine skyline heightforeach(varxinpoints){intmaxH=0;// Check which buildings cover the // current x and get the max heightforeach(varbinbuild){intl=b[0],r=b[1],h=b[2];if(l<=x&&x<r){maxH=Math.Max(maxH,h);}}// Add to result if height has changedif(res.Count==0||maxH!=prev){res.Add(newint[]{x,maxH});prev=maxH;}}returnres;}publicstaticvoidMain(string[]args){int[][]build={newint[]{2,9,10},newint[]{3,6,15},newint[]{5,12,12}};Solutionsol=newSolution();varskyline=sol.GetSkyline(build);foreach(varpinskyline){Console.Write("("+p[0]+", "+p[1]+") ");}Console.WriteLine();}}
JavaScript
functiongetSkyline(build){constpoints=[];// Collect all left and right x-coordinates// of buildingsfor(constbofbuild){points.push(b[0]);points.push(b[1]);}// Sort all critical pointspoints.sort((a,b)=>a-b);constres=[];letprev=0;// Traverse through each point to// determine skyline heightfor(constxofpoints){letmaxH=0;// Check which buildings cover the // current x and get the max heightfor(constbofbuild){const[l,r,h]=b;if(l<=x&&x<r){maxH=Math.max(maxH,h);}}// Add to result if height has changedif(res.length===0||maxH!==prev){res.push([x,maxH]);prev=maxH;}}returnres;}constbuild=[[2,9,10],[3,6,15],[5,12,12]];constskyline=getSkyline(build);for(constpofskyline){process.stdout.write(`(${p[0]}, ${p[1]}) `);}console.log();
Output
(2, 10) (3, 15) (6, 12) (12, 0)
Using Sweep Line and Priority Queue - O(n Log n) Time and O(n) Space
The problem can be approached using a sweep line algorithm with a priority queue (max-heap) to maintain the heights of the buildings as the sweep line moves from left to right. The idea is to again store all points, but this time we also store building indexes. We use priority queue to have all building point in it when we reach the next points, so that we can quickly find the maximum.
Here’s a step-by-step explanation:
Prepare Edges: For each building, store two edges (start and end) as a pair of coordinates: (x-coordinate, building index). This helps in processing all the building edges.
Sort Edges: Sort the edges based on the x-coordinate. If two edges have the same x-coordinate, prioritize the left edges (start) over the right ones (end).
Use Priority Queue: Traverse the sorted edges and maintain a priority queue that holds the current building heights (from the start edges) as well as their right endpoints.
Process Each Edge: For each x-coordinate:
Add building heights when encountering a start edge.
Remove building heights when encountering an end edge (pop from the priority queue).
The current maximum height in the priority queue represents the height at the current x-coordinate.
Add to Skyline: If the current height is different from the previous height, record the x-coordinate and height as a new point in the skyline.
Return Result: The result is the list of (x-coordinate, height) pairs representing the visible parts of the skyline.
C++
#include<iostream>#include<vector>#include<queue>#include<algorithm>usingnamespacestd;vector<vector<int>>getSkyline(vector<vector<int>>&arr){vector<pair<int,int>>e;priority_queue<pair<int,int>>pq;vector<vector<int>>skyline;intn=arr.size();for(inti=0;i<n;++i){e.push_back({arr[i][0],i});// starte.push_back({arr[i][1],i});// end}sort(e.begin(),e.end());// Traverse sorted edgesinti=0;while(i<e.size()){intcurr_height;intcurr_x=e[i].first;// Add all buildings starting or ending// at current xwhile(i<e.size()&&e[i].first==curr_x){intidx=e[i].second;// Push building height and end xif(arr[idx][0]==curr_x)pq.emplace(arr[idx][2],arr[idx][1]);++i;}// Remove buildings that have endedwhile(!pq.empty()&&pq.top().second<=curr_x)pq.pop();curr_height=pq.empty()?0:pq.top().first;if(skyline.empty()||skyline.back()[1]!=curr_height)skyline.push_back({curr_x,curr_height});}returnskyline;}intmain(){vector<vector<int>>arr={{1,5,11},{2,7,6},{3,9,13},{12,16,7},{14,25,3},{19,22,18},{23,29,13},{24,28,4}};vector<vector<int>>result=getSkyline(arr);for(constauto&p:result){cout<<"["<<p[0]<<", "<<p[1]<<"] ";}cout<<endl;return0;}
usingSystem;usingSystem.Collections.Generic;classSkyline{publicstaticList<List<int>>GetSkyline(int[,]arr,intn){intidx=0;List<int[]>e=newList<int[]>();SortedSet<int[]>pq=newSortedSet<int[]>(Comparer<int[]>.Create((a,b)=>a[0].CompareTo(b[0])));List<List<int>>skyline=newList<List<int>>();for(inti=0;i<n;i++){e.Add(newint[]{arr[i,0],i});e.Add(newint[]{arr[i,1],i});}e.Sort((a,b)=>a[0].CompareTo(b[0]));while(idx<e.Count){intcurr_x=e[idx][0];while(idx<e.Count&&curr_x==e[idx][0]){intbuilding_idx=e[idx][1];if(arr[building_idx,0]==curr_x)pq.Add(newint[]{arr[building_idx,2],arr[building_idx,1]});// Add building height and end pointidx++;}while(pq.Count>0&&pq.Min[1]<=curr_x)pq.Remove(pq.Min);intcurr_height=pq.Count==0?0:pq.Min[0];if(skyline.Count==0||skyline[skyline.Count-1][1]!=curr_height)skyline.Add(newList<int>{curr_x,curr_height});}returnskyline;}staticvoidMain(string[]args){int[,]arr={{1,5,11},{2,7,6},{3,9,13},{12,16,7},{14,25,3},{19,22,18},{23,29,13},{24,28,4}};intn=8;varresult=GetSkyline(arr,n);foreach(varpinresult){Console.Write($"[{p[0]}, {p[1]}] ");}Console.WriteLine();}}
We use cookies to ensure you have the best browsing experience on our website. By using our site, you
acknowledge that you have read and understood our
Cookie Policy &
Privacy Policy
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.