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] = [lefti, righti, heighti]:
lefti is the x coordinate of the left edge of the ith building.
righti is the x coordinate of the right edge of the ith building.
heighti is the height of the ith building.
You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
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 0 and is used to mark the skyline's termination where the rightmost building ends. Any ground between the leftmost and rightmost buildings should be part of the skyline's contour.
Note: There must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...,[2 3],[4 5],[7 5],[11 5],[12 7],...] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...,[2 3],[4 5],[12 7],...]
Ex.
class Solution:
def getSkyline(self, buildings: List[List[int]]) -> List[List[int]]:
events = []
ans = []
for s, e, h in buildings:
events.append((s, -h))
events.append((e, h))
events.sort()
height = [0]
remove_list = defaultdict(int)
prev = 0
for i, h in events:
if h < 0:
heappush(height, h)
else:
remove_list[h] += 1
curr = -height[0]
while remove_list[curr] > 0:
remove_list[curr] -= 1
heappop(height)
curr = -height[0]
if curr != prev:
ans.append([i, curr])
prev = curr
return ans
events = []
ans = []
for s, e, h in buildings:
events.append((s, -h))
events.append((e, h))
이후
1 events.sort()
2
3 height = [0]
4 remove_list = defaultdict(int)
5 prev = 0
6
7 for i, h in events:
8 if h < 0:
9 heappush(height, h)
10 else:
11 remove_list[h] += 1
12
13 curr = -height[0]
14 while remove_list[curr] > 0:
15 remove_list[curr] -= 1
16 heappop(height)
17 curr = -height[0]
18
19 if curr != prev:
20 ans.append([i, curr])
21 prev = curr
1번 줄
: 이벤트 정렬
3~5번 줄
: 사용할 힙과 prev
prev : 높이가 변경될 때에만 저장되기에, 높이의 변경 여부를 확인해야 함
8~9번 줄
: 건물이 세워지면 MaxHeap에 건물의 높이를 넣는다
즉, 세워진 건물의 가장 큰 높이를 계속 추적한다.
9~10번 줄
: 건물이 내려가면, 삭제할 건물 리스트에 올려둔다.
13~17번 줄
: 현재 가장 높은 건물에 해당하는 높이에 대해서, 해당 높이가 이미 끝난 건물인지 확인하고, 끝났으면 pop한다.
이때 heappop을 그대로 사용가능해 시간복잡도상 유리해진다.
만약 remove_list를 쓰지 않고 list의 remove를 쓴다면 코드는 간단해 지지만, O(N^2)의 시간복잡도가 되어 버린다.
19~21번 줄
: 끝난 건물들을 다 정리하고 남은 가장 높은 건물의 높이가 이전 높이와 다르다면, 정답에 추가
if -height[0] != prev:
ans.append([i, -height[0]])
prev = -height[0]
여기서 curr은 가장 높으면서 끝나지 않은 건물을 의미하기에, 사실 이렇게 heap을 사용해도 정답은 변하지 않는다.
class Solution:
def getSkyline(self, buildings: List[List[int]]) -> List[List[int]]:
events = []
ans = []
for s, e, h in buildings:
events.append((s, -h))
events.append((e, h))
events.sort()
height = [0]
remove_list = defaultdict(int)
prev = 0
for i, h in events:
if h < 0:
heappush(height, h)
else:
remove_list[h] += 1
while remove_list[-height[0]] > 0:
remove_list[-height[0]] -= 1
heappop(height)
if -height[0] != prev:
ans.append([i, -height[0]])
prev = -height[0]
return ans