题目:
城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 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
}