leetcode刷题笔记 218题 天际线问题
leetcode刷题笔记 218题 天际线问题
源地址:218. 天际线问题
问题描述:
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)。
每个建筑物的几何信息用三元组 [Li,Ri,Hi] 表示,其中 Li 和 Ri 分别是第 i 座建筑物左右边缘的 x 坐标,Hi 是其高度。可以保证 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX 和 Ri - Li > 0。您可以假设所有建筑物都是在绝对平坦且高度为 0 的表面上的完美矩形。
例如,图A中所有建筑物的尺寸记录为:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] 。
输出是以 [ [x1,y1], [x2, y2], [x3, y3], ... ] 格式的“关键点”(图B中的红点)的列表,它们唯一地定义了天际线。关键点是水平线段的左端点。请注意,最右侧建筑物的最后一个关键点仅用于标记天际线的终点,并始终为零高度。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
例如,图B中的天际线应该表示为:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]。
说明:
任何输入列表中的建筑物数量保证在 [0, 10000] 范围内。
输入列表已经按左 x 坐标 Li 进行升序排列。
输出列表必须按 x 位排序。
输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
//使用扫描线法,基于数据结构TreeMap(底层为红黑树)
//TreeMap相关知识参考:https://www.cnblogs.com/LiaHon/p/11221634.html
//https://www.scala-lang.org/api/current/scala/collection/mutable/TreeMap.html
import scala.collection.mutable
object Solution {
//样例类 继承 Oredered特质, 并且重写compare方法
case class Point(x: Int, y: Int, isEnd: Boolean) extends Ordered[Point] {
override def compare(other: Point): Int = {
if (x != other.x) return x - other.x
else if (isEnd && other.isEnd) return y - other.y
else if (!isEnd && !other.isEnd) return other.y - y
else if (isEnd == true) return 1
else return -1
}
}
def getSkyline(buildings: Array[Array[Int]]): List[List[Int]] = {
//将builds 拆分为 矩阵x轴的首尾坐标与高度值结合
val points = buildings.map(x => {Array(Point(x(0), x(2), false), Point(x(1), x(2), true))}).flatten.sorted
//println(points.mkString(" "))
val res = mutable.ListBuffer[List[Int]]()
val tm = new mutable.TreeMap[Int, Int]()
tm.put(0, 1)
for (point <- points){
//println(point.toString)
var prevMax = tm.lastKey
//println("prevMax: " + prevMax)
//矩形尾部位置,将消除高度值
if (point.isEnd == true) {
val currentCount = tm.getOrElse(point.y, 0)
tm.remove(point.y)
if (currentCount > 1) {
tm.put(point.y, currentCount-1)
}
}
//矩阵头部位置,记录高度
else{
if (tm.contains(point.y)){
val currentCount = tm.getOrElse(point.y, 0)
tm.remove(point.y)
tm.put(point.y, currentCount+1)
}
else{
tm.put(point.y, 1)
}
}
//若高度发生变化,则说明其为转折点,将其加入res
val curMax = tm.lastKey
println("curMax: " + curMax)
if (prevMax != curMax) {
res += List(point.x, curMax)
}
}
return res.toList
}
}