In [3]:
1
2
3
4
5
import heapq, sys
sys.path.append("/home/swyoo/algorithm/")
from utils.verbose import logging_time
from typing import List
INF = 1e20
In [5]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution1(object):
    @logging_time
    def getSkyline(self, buildings: List[List[int]]):
        def func(s, e):
            if s == e:
                l, r, h = buildings[s]
                return [[l, h], [r, 0]]
            mid = (s + e) // 2
            left = func(s, mid)
            right = func(mid + 1, e)

            def merge(left, right):
                """ left and right are skyline. """
                h1 = h2 = i = j = 0
                n1, n2 = len(left), len(right)
                left.append([INF, 0])
                right.append([INF, 0])
                cross = []

                def append(x, strip):
                    """ append a strip to x
                    :type x: 2D list with size [[2]*]
                    :rtype: 1D list with size 2
                    """
                    # # Check for redundant strip, a strip is redundant if it has same height or left as previous
                    if len(x) > 0 and x[-1][1] == strip[1]: # height is same
                        return
                    elif len(x) > 0 and x[-1][0] == strip[0]:  # left is same
                        x[-1][1] = max(x[-1][1], strip[1])
                        return
                    # general case
                    x.append(strip)

                for _ in range(n1 + n2):
                    if left[i][0] < right[j][0]:
                        h1 = left[i][1]
                        append(cross, [left[i][0], max(h1, h2)])
                        i += 1
                    else:
                        h2 = right[j][1]
                        append(cross, [right[j][0], max(h1, h2)])
                        j += 1
                cross[-1][1] = 0  # end's height is always 0
                return cross

            return merge(left, right)
        return func(0, len(buildings) - 1)

sol1 = Solution1()
In [7]:
1
2
3
buildings = [[1,2,1],[1,2,2],[1,2,3]]
# buildings = [[2, 9, 10], [3, 7, 15], [5, 12, 12], [15, 20, 10], [19, 24, 8]]
print("answer:", sol1.getSkyline(buildings, verbose=True))
1
2
3
WorkingTime[getSkyline]: 0.04101 ms
answer: [[1, 3], [2, 0]]

In [13]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution2(object):
    @logging_time
    def getSkyline(self, buildings: List[List[int]]):
        # sort by (L, -H, R) increasing order
        # end building events 도 넣는다.
        events = sorted([(L, -H, R) for L, R, H in buildings] + list({(R, 0, 0) for _, R, _ in buildings}))
        # print(events)
        res, hp = [[0, 0]], [(0, 1e20)]  # dummy 값들
        # intuition
        # 1, pop buildings that are already ended
        # 2, if it's the start-building event, make the building alive
        # 3, if previous keypoint height != current highest height, edit the result
        for x, negH, R in events:
            while x >= hp[0][1]:
                heapq.heappop(hp)
            if negH:
                heapq.heappush(hp, (negH, R))
            if res[-1][1] + hp[0][0]:
                res.append([x, -hp[0][0]])
        return res[1:]

sol = Solution2()
In [14]:
1
sol.getSkyline(buildings, verbose=True)
1
2
WorkingTime[getSkyline]: 0.03839 ms

1
[[1, 3], [2, 0]]

Leave a comment