【leetcode-归并/单调队列】天际线问题

城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回由这些建筑物形成的 天际线 。

每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [ l e f t i left_i lefti, r i g h t i right_i righti, h e i g h t i height_i heighti] 表示:

  • l e f t i left_i lefti 是第 i 座建筑物左边缘的 x 坐标。
  • r i g h t i right_i righti 是第 i 座建筑物右边缘的 x 坐标。
  • h e i g h t i height_i 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], …]

优先队列排序当前最大高度

在这里插入图片描述

class Solution {
    class Point {
        int x;
        int y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    public List<List<Integer>> getSkyline(int[][] buildings) {
        List<Point> points = new ArrayList<>();
        for (int i = 0; i < buildings.length; i++) {
            Point p1 = new Point(buildings[i][0], -buildings[i][2]);
            Point p2 = new Point(buildings[i][1], buildings[i][2]);
            points.add(p1);
            points.add(p2);
        }

        Collections.sort(points, new Comparator<Point>() {
            @Override
            public int compare(Point p1, Point p2) {
                if (p1.x != p2.x)
                    return p1.x - p2.x;
                else
                    return p1.y - p2.y;
            }
        });

        Queue<Integer> heights = new PriorityQueue<>((h1, h2) -> h2 - h1);
        heights.offer(0);
        int curHeight = 0;
        List<List<Integer>> result = new ArrayList<>();
        for (Point p : points) {
            if (p.y < 0)
                heights.offer(-p.y);
            else
                heights.remove(p.y);
            if (curHeight != heights.peek()) {
                curHeight = heights.peek();
                List<Integer> point = new ArrayList<>();
                point.add(p.x);
                point.add(curHeight);
                result.add(point);
            }
        }
        return result;
    }
}

归并

class Solution {
    public List<List<Integer>> getSkyline(int[][] buildings) {
        int len = buildings.length;
        if(len == 0)
            return  new ArrayList<>();
        return merge(buildings, 0, len - 1);
    }

    private List<List<Integer>> merge(int[][] buildings, int start, int end) {
        List<List<Integer>> result = new ArrayList<>();
        if (start == end) {
            List<Integer> point = new ArrayList<>();
            point.add(buildings[start][0]);
            point.add(buildings[start][2]);
            result.add(point);

            point = new ArrayList<>();
            point.add(buildings[start][1]);
            point.add(0);
            result.add(point);
            return result;
        }

        int mid = (start + end) / 2;
        List<List<Integer>> skyline1  = merge(buildings, start, mid);
        List<List<Integer>> skyline2  = merge(buildings, mid + 1, end);

        int len1 = skyline1.size(), len2 = skyline2.size();
        int i = 0, j = 0;
        int height1 = 0, height2 = 0, prevHeight = 0;
        while (i < len1 || j < len2) {
            long x1 = i < len1 ? skyline1.get(i).get(0) : Long.MAX_VALUE;
            long x2 = j < len2 ? skyline2.get(j).get(0) : Long.MAX_VALUE;
            int x = 0;
            if (x1 < x2) {
                height1 = skyline1.get(i++).get(1);
                x = (int)x1;
            } else if (x1 > x2) {
                height2 = skyline2.get(j++).get(1);
                x = (int)x2;
            } else {
                height1 = skyline1.get(i++).get(1);
                height2 = skyline2.get(j++).get(1);
                x = (int)x1;
            }
            
            int currHeight = Math.max(height1, height2);
            if (currHeight != prevHeight) {
                List<Integer> point = new ArrayList<>();
                point.add(x);
                point.add(currHeight);
                result.add(point);
            }
            prevHeight = currHeight;
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值