水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用一个三元组表示 (start, end, height)
,分别代表其在x轴上的起点,终点和高度。大楼之间从远处看可能会重叠,求出 N 座大楼的外轮廓线。
外轮廓线的表示方法为若干三元组,每个三元组包含三个数字 (start, end, height),代表这段轮廓的起始位置,终止位置和高度。
public class Solution {
/**
* @param buildings: A list of lists of integers
* @return: Find the outline of those buildings
*/
class Node {
int x;//x轴上的值
boolean isAdd;//true是增加高度 false是降低高度
int h;//操作高度的大小
public Node(int x, boolean isAdd, int h) {
this.x = x;
this.isAdd = isAdd;
this.h = h;
}
}
//Node类型的比较器 先比较x轴上的值 相同的情况下 add操作在前(防止竖状大楼导致代码出错) 如果操作类型相同的话则认为两个对象相等 谁在前都可以
public class NodeComparer 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 List<List<Integer>> buildingOutline(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 NodeComparer());
//创建两张有序表 一张记录高度的出现次数 次数小于0后删除该高度
//一张记录x处的最大高度 从map1中获取得到目前表内的最大高度
TreeMap<Integer, Integer> mapHeightTimes = new TreeMap<>();
TreeMap<Integer, Integer> mapXHeight = new TreeMap<>();
for (Node node : nodes) {//遍历nodes节点
if (node.isAdd) {//如果当前的操作是添加操作
if (!mapHeightTimes.containsKey(node.h)) {//如果高度次数map中没有该高度则添加进map
mapHeightTimes.put(node.h, 1);
} else {
mapHeightTimes.put(node.h, mapHeightTimes.get(node.h) + 1);
}
} else {//当前操作是一个删除操作
if (mapHeightTimes.get(node.h) == 1) {//如果当前高度的词频是1直接删除该高度
mapHeightTimes.remove(node.h);
} else {//次数大于1就减少次数1此
mapHeightTimes.put(node.h, mapHeightTimes.get(node.h) - 1);
}
}
//根据mapHeightTimes来添加x轴的最大高度表
if (mapHeightTimes.isEmpty()) {//高度为空 则最大高度为0
mapXHeight.put(node.x, 0);
} else {//如果map不为空 获得目前表中的最大高度mapHeightTimes.lastKey()
mapXHeight.put(node.x, mapHeightTimes.lastKey());
}//现在所有的x点的高度变化信息已经在mapXHeight中
}
//res为结果数组 每一个List<Integer>代表一个轮廓线 有开始位置结束位置 高度
List<List<Integer>> res = new ArrayList<>();
//一个新轮廓线的开始
int start = 0;
//一个轮廓线的结束
int end = 0;
//之前的最大高度
int preHeigh = 0;
for (Map.Entry<Integer, Integer> entry : mapXHeight.entrySet()) {
Integer curX = entry.getKey();//当前位置
//当前最大高度
Integer curMaxHeight = entry.getValue();
if (curMaxHeight != preHeigh) {
if (preHeigh != 0) {
res.add(new ArrayList<>(Arrays.asList(start, curX, preHeigh)));
}
start = curX;
preHeigh = curMaxHeight;
}
}
return res;
}
}