前言
城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [lefti, righti, heighti] 表示:
lefti 是第 i 座建筑物左边缘的 x 坐标。
righti 是第 i 座建筑物右边缘的 x 坐标。
heighti 是第 i 座建筑物的高度。
你可以假设所有的建筑都是完美的长方形,在高度为 0 的绝对平坦的表面上。
天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...] ,并按 x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y 坐标始终为 0 ,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/the-skyline-problem
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、解题思路
轮廊线怎么去找?
轮廓线的产生只来自于最大高度的变化。
二、解题步骤
怎么追踪最大高度
首先我们要定义一种对象Node
Node里面记录这每一个点的位置X
高度是否上升isAdd 上升为true,下降为false
生成对象数组,每一个数组元素对应两个对象,分别为加高度和减高度
对象安装下标来排序
public class NodeComparator implements Comparator<Node>{
public int compare(Node o1,Node o2){
return o1.x-o2.x;
}
}
public List<List<Integer>> getSkyline(int[][] buildings) {
int n=buildings.length;
Node[] nodes=new Node[n*2];
for(int i=0;i<n;i++){
nodes[i*2]=new Node(buildings[i][0],true,buildings[i][2]);
nodes[i*2+1]=new Node(buildings[i][1],false,buildings[i][2]);
}
Arrays.sort(nodes,new NodeComparator());
准备一个有序表map
key代表高度,按照有序组织, value代表这个高度加入的次数
加入之后,有序表中拿出最大的key, logN复杂度,我就可以知道最大高度的变化
1位置加了高度4,次数变成2,最大高度没有变化,还是4
2位置加了高度5,次数1,我就知道在2位置最大高度由4变成了5
点的高度h
6位置减一个高度5,减成了0,记录删掉,我就知道此时最大高度由5回到了4
7位置减一个4,只减了一次,最大高度没有变化
8位置又减了一个4,次数0,整条记录干掉,最大高度回到0
为什么我要把高度设计成次数的,因为有可能有多个高度并存,而我删只能删一次
总结
如果有N个大楼导出2N个对象,因为一个大楼有在某个时刻加一个高度,在某个时刻减一个高度,这2N个对象只根据第一维数据排序。在同一个位置做加加减减。你就会知道X轴每一个你需要关心的点,它最大高度最终变成了啥,以最后一次为准。你有了这么一个过程,你生成轮廊线是就搞定了。
import java.util.Map.Entry;
class Solution {
public class Node{
public int x;
public boolean isAdd;
public int h;
public Node(int x,boolean isAdd,int h){
this.x=x;
this.isAdd=isAdd;
this.h=h;
}
}
public class NodeComparator implements Comparator<Node>{
public int compare(Node o1,Node o2){
return o1.x-o2.x;
}
}
public List<List<Integer>> getSkyline(int[][] buildings) {
int n=buildings.length;
Node[] nodes=new Node[n*2];
for(int i=0;i<n;i++){
nodes[i*2]=new Node(buildings[i][0],true,buildings[i][2]);
nodes[i*2+1]=new Node(buildings[i][1],false,buildings[i][2]);
}
Arrays.sort(nodes,new NodeComparator());
TreeMap<Integer,Integer> mapHeightTime=new TreeMap<>();
TreeMap<Integer,Integer> mapXHeight=new TreeMap<>();
for(int i=0;i<nodes.length;i++){
if(nodes[i].isAdd){
if(!mapHeightTime.containsKey(nodes[i].h)){
mapHeightTime.put(nodes[i].h,1);
}else{
mapHeightTime.put(nodes[i].h,mapHeightTime.get(nodes[i].h)+1);
}
}else{
if(mapHeightTime.get(nodes[i].h)==1){
mapHeightTime.remove(nodes[i].h);
}else{
mapHeightTime.put(nodes[i].h,mapHeightTime.get(nodes[i].h)-1);
}
}
if(mapHeightTime.isEmpty()){
mapXHeight.put(nodes[i].x,0);
}else{
mapXHeight.put(nodes[i].x,mapHeightTime.lastKey());
}
}
List<List<Integer>> ans = new ArrayList<>();
for (Entry<Integer, Integer> entry : mapXHeight.entrySet()) {
int curX = entry.getKey();
int curMaxHeight = entry.getValue();
if (ans.isEmpty() || ans.get(ans.size() - 1).get(1) != curMaxHeight) {
ans.add(new ArrayList<>(Arrays.asList(curX, curMaxHeight)));
}
}
return ans;
}
}