LeetCode-218-天际线问题
218. 天际线问题
难度困难
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 buildings
表示,其中三元组 buildings[i] = [lefti, righti, heighti]
表示:
-
lefti
是第i
座建筑物左边缘的x
坐标。 -
righti
是第i
座建筑物右边缘的x
坐标。 -
heighti
是第i
座建筑物的高度。
天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...]
,并按 x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y
坐标始终为 0
,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...]
是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
示例 1:
输入:buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
输出:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
解释:
图 A 显示输入的所有建筑物的位置和高度,
图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。
示例 2:
输入:buildings = [[0,2,3],[2,5,3]]
输出:[[0,3],[5,0]]
提示:
1 <= buildings.length <= 104
0 <= lefti < righti <= 231 - 1
1 <= heighti <= 231 - 1
-
buildings
按lefti
非递减排序
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;
import java.util.Map.Entry;
class Solution {
public static 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 static class NodeComparator implements Comparator<Node> {
@Override
public int compare(Node o1, Node o2) {
if (o1.x != o2.x) {
return o1.x - o2.x;
}
if (o1.isAdd != o2.isAdd) {
return o1.isAdd ? -1 : 1;
}
return 0;
}
}
public static List<List<Integer>> getSkyline(int[][] matrix) {
Node[] nodes = new Node[matrix.length * 2];
for (int i = 0; i < matrix.length; i++) {
nodes[i * 2] = new Node(matrix[i][0], true, matrix[i][2]);
nodes[i * 2 + 1] = new Node(matrix[i][1], false, matrix[i][2]);
}
Arrays.sort(nodes, new NodeComparator());//根据index节点排序
// 有序表,key 代表某个高度 value 这个高度出现的次数
TreeMap<Integer, Integer> mapHeightTimes = new TreeMap<>();
// 有序表 key x的值 value 处在x位置时的高度
TreeMap<Integer, Integer> xMaxHeight = new TreeMap<>();
for (int i = 0; i < nodes.length; i++) {
if (nodes[i].isAdd) {
if (!mapHeightTimes.containsKey(nodes[i].h)) {//高度不存在
mapHeightTimes.put(nodes[i].h, 1);//加入高度
} else {
mapHeightTimes.put(nodes[i].h, mapHeightTimes.get(nodes[i].h) + 1);//高度存在,value+1
}
} else {//减法
if (mapHeightTimes.get(nodes[i].h) == 1) {
mapHeightTimes.remove(nodes[i].h);//value=1,删除红黑树节点
} else {
mapHeightTimes.put(nodes[i].h, mapHeightTimes.get(nodes[i].h) - 1);//高度存在,value-1
}
}
if (mapHeightTimes.isEmpty()) {
xMaxHeight.put(nodes[i].x, 0);//红黑树没有节点,当前x的值为0 上图例子中的[12,0]
} else {
xMaxHeight.put(nodes[i].x, mapHeightTimes.lastKey());//当前x加入结束(减法结束)后的红黑树的最大值
}
}
List<List<Integer>> ans = new ArrayList<>();//收集每个点X的最大值答案
for (Entry<Integer, Integer> entry : xMaxHeight.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;
}
}