218.天际线问题

115 阅读2分钟

题目:
城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。

每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [lefti, righti, heighti] 表示:

  • lefti 是第 i 座建筑物左边缘的 x 坐标。
  • righti 是第 i 座建筑物右边缘的 x 坐标。
  • heighti 是第 i 座建筑物的高度。

解法:
方法一:堆
只在左端点或者右端点出现时,天际线会变化,和左右端点的跨度没有关系。
天际线的关键点在建筑左边缘时,和当前建筑的高度有关;
关键点在建筑右边缘时,和移除当前建筑后的最大建筑高度有关。
分析到这里可以看到这种特性适合用堆处理。

import "container/heap"
func getSkyline(buildings [][]int) [][]int {
    h := newHeap()
    ans := make([][]int, 0)

    // points保存坐标以及高度,高度为负数表示建筑左边缘
    points := make([][]int, 0 )
    for i := range buildings {
        points = append(points, []int{buildings[i][0], -buildings[i][2]})
        points = append(points, []int{buildings[i][1], buildings[i][2]})
    }
    // 按横坐标大小排序,横坐标相同时,左边缘高度高的优先处理,右边缘高度低的优先处理。
    // 因为建筑进入后和离开后最高点决定关键点
    sort.Slice(points, func(i, j int) bool {
        if points[i][0] != points[j][0] {
            return points[i][0] < points[j][0]
        }
        return points[i][1] < points[j][1]
    })
    preHeight := 0
    heap.Push(h, preHeight)
    for i := range points {
        if points[i][1] < 0 {
            heap.Push(h, -points[i][1])
        } else {
            index := h.lowBound(points[i][1])
            // fmt.Println(index, *h)
            heap.Remove(h, index)
        }
        curHeight := h.Top().(int)
        if curHeight != preHeight {
            ans = append(ans, []int{points[i][0], curHeight})
            // heap.Pop(h)
            preHeight = curHeight
        }
    }
    return ans
}

type Heap []int 
func (h Heap) Less(i, j int) bool {return h[i] > h[j]}
func (h Heap) Swap(i, j int) { h[i], h[j] = h[j], h[i]}
func (h Heap) Len() int {return len(h)}
func (h *Heap) Pop() interface{} {
    n := len(*h)
    old := *h
    x := old[n - 1]
    *h = old[:n - 1]
    return x
}
func (h *Heap) Push(x interface{})  {
    *h = append(*h, x.(int))
}

func (h *Heap) Top() interface{} {
    old := *h
    return old[0]
}

func newHeap() *Heap {
    return &Heap{}
}

func (h *Heap) lowBound(x int) int {
    arr := *h
    for i := range arr {
        if x == arr[i] {
            return i
        }
    }
    return - 1
}