leetcode 218. 天际线问题(The Skyline Problem)

这里写图片描述

  1. 首先要画出轮廓线,其实就是画轮廓点,而轮廓点显示就是在建筑的左上右上顶点中,问题转化为找符合条件的顶点。
  2. 每个没被遮挡的高建筑左顶点一定是轮廓点;高建筑和矮建筑交汇的地方,取的是高建筑右顶点的横坐标和矮建筑的高度作为轮廓点;每一片连在一起的建筑的最右边的轮廓点,纵坐标取0
  3. 这题网上最主流的解法是用大顶堆来解,看了很久才理解,这里尝试解释一下:

    1. 将每条建筑的横线段分解成左上右上两个顶点,将所有这些点按横坐标大小升序排列
    2. 从左至右遍历这些点,每遍历到一个左顶点,将此点代表的建筑高度放入大顶堆height中
    3. 每次到一个左顶点,先比较此顶点高度与当前基准高度,如果高于基准高度,那么就是一个轮廓点。这是最关键的地方,结合图形理解,如果当前建筑的左顶点要作比较,肯定是与它前面有重叠的建筑比较,而前面重叠的建筑高度,要取之前最高的、横线还在延续的建筑比较,因此需要用到一个大顶堆维护当前高度

还有两个细节:
1. 将右顶点的高度设为负值,在遍历点时用以区分左右顶点
2. 碰到左顶点将高度加入大顶堆,碰到右顶点时,说明此建筑横向的延绵结束了,那么要从大顶堆中删掉此高度

public List<int[]> getSkyline(int[][] buildings) {
        List<int[]> list = new ArrayList<int[]>();
        Set<int []>set = new TreeSet<int[]>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {//每个顶点先横坐标排序
                if(o1[0] == o2[0]){//横坐标相同时,纵坐标要降序排列
                    return o2[1] - o1[1];
                }
                return o1[0] - o2[0];
            }
        });
        //高度降序优先队列(大顶堆)
        PriorityQueue<Integer> height = new PriorityQueue<Integer>(11,new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        //构造顶点横坐标升序set
        for(int i=0;i<buildings.length;i++){
            int[] A = {buildings[i][0],buildings[i][2]};
            set.add(A);
            //右顶点y值设为负值,便于区分
            int[] B = {buildings[i][1],-1*buildings[i][2]};
            set.add(B);
        }
        //遍历set
        height.offer(0);
        int preHeight = 0;
        for(int[] A : set){
            if(A[1] > 0){//左顶点
                if(A[1] > preHeight){//左顶点大于上一高度
                    list.add(A);
                }

                height.offer(A[1]);//加入当前线段高度
                preHeight = height.peek();//拿顶部元素作为上次高度
            }
            else{
                height.remove(-1*A[1]);//右顶点时去掉大顶堆对应左顶点
                preHeight = height.peek();//拿顶部元素作为上次高度
                if(-1*A[1] > preHeight){//右顶点大于上一高度
                    int []temp = {A[0],preHeight};
                    list.add(temp);
                }

            }
        }
        return list;
    }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值