给定一个 N×3 的矩阵 matrix,对于每一个长度为 3 的小数组 arr,都表示一个大楼的三个数据,请返回整体的轮廓线数组。

问题描述

        给定一个 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);
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值