问题描述
给定一个 N×3 的矩阵 matrix,对于每一个长度为 3 的小数组 arr,都表示一个大楼的三个数 据。arr[0]表示大楼的左边界,arr[1]表示大楼的右边界,arr[2]表示大楼的高度(一定大于 0)。 每座大楼的地基都在 X 轴上,大楼之间可能会有重叠,请返回整体的轮廓线数组。
【举例】 matrix ={{2,5,6}, {1,7,4}, {4,6,7}, {3,6,5}, {10,13,2}, {9,11,3}, {12,14,4},{10,12,5} }
返回: {{1,2,4},{2,4,6}, {4,6,7}, {6,7,4}, {9,10,3}, {10,12,5}, {12,14,4}}
代码
//描述高度变化的对象
public static class Op {
public int x;//x轴上的值
public boolean isAdd;//true为加入,false为删除
public int h;//高度
public Op(int x, boolean isAdd, int h) {
this.x = x;
this.isAdd = isAdd;
this.h = h;
}
}
/**
* 排序的比较策略
* 1.第一个维度的X值从小到大。
* 2.如果第一个维度的值相同,看第二个维度的值,“加入”排在前,“删除”排在后
* 3.如果两个对象第一维度和第二个维度的值都相同,则认为两个对象相同,谁在前都行
*/
public static class OpComparator implements Comparator<Op> {
@Override
public int compare(Op o1, Op 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>> buildingOutline(int[][] matrix) {
int N = matrix.length;
Op[] ops = new Op[N << 1];
for (int i = 0; i < matrix.length; i++) {
ops[i * 2] = new Op(matrix[i][0], true, matrix[i][2]);
ops[i * 2 + 1] = new Op(matrix[i][1], false, matrix[i][2]);
}
//把描述高度变化的对象数组,按照规定的排序策略排序
Arrays.sort(ops, new OpComparator());
// key : 某个高度 value : 次数
TreeMap<Integer, Integer> mapHeightTimes = new TreeMap<>();
// key : x点 value : 最大高度
TreeMap<Integer, Integer> mapXHeight = new TreeMap<>();
for (int i = 0; i < ops.length; i++) {
//如果当前是加入操作
if (ops[i].isAdd) {
//没有出现的高度
if (!mapHeightTimes.containsKey(ops[i].h)) {
mapHeightTimes.put(ops[i].h, 1);
} else {//之前出现的高度,次数加一即可
mapHeightTimes.put(ops[i].h, mapHeightTimes.get(ops[i].h) + 1);
}
} else {//如果当前是删除操作
//如果当前的高度出现的次数为1,直接删除
if (mapHeightTimes.get(ops[i].h) == 1) {
mapHeightTimes.remove(ops[i].h);
} else {//如果当前高度出现的次数大于1,次数减1即可
mapHeightTimes.put(ops[i].h, mapHeightTimes.get(ops[i].h) - 1);
}
}
//根据mapHeightTimes中的最大高度,设置mapXHeight
//mapHeightTimes为空,说明最大高度为0
if (mapHeightTimes.isEmpty()) {
mapXHeight.put(ops[i].x, 0);
} else {
//mapHeightTimes不为空,获取最大高度
mapXHeight.put(ops[i].x, mapHeightTimes.lastKey());
}
}
//res为结果数组,每一个List<Integer>代表一个轮廓线,有开始位置,结束位置,高度一共三个信息
List<List<Integer>> res = new ArrayList<>();
//一个新轮廓线的开始位置
int start = 0;
//之前的最大高度
int preHeight = 0;
for (Map.Entry<Integer, Integer> entry : mapXHeight.entrySet()) {
//当前位置
int curX = entry.getKey();
//当前最大高度
int curMaxHeight = entry.getValue();
//之前最大高度和当前最大高度不一样时
if (preHeight != curMaxHeight) {
if (preHeight != 0) {
res.add(new ArrayList<>(Arrays.asList(start, curX, preHeight)));
}
start = curX;
preHeight = curMaxHeight;
}
}
return res;
}
public static void main(String[] args) {
int[][] matrix = {
{2, 5, 6},
{1, 7, 4},
{4, 6, 7},
{3, 6, 5},
{10, 13, 2},
{9, 11, 3},
{12, 14, 4},
{10, 12, 5}
};
List<List<Integer>> res = buildingOutline(matrix);
System.out.println(res);
}