LeetCode每日一题(218. The Skyline Problem)

A city’s skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Given the locations and heights of all the buildings, return the skyline formed by these buildings collectively.

The geometric information of each building is given in the array buildings where buildings[i] = [lefti, righti, heighti]:

lefti is the x coordinate of the left edge of the ith building.
righti is the x coordinate of the right edge of the ith building.
heighti is the height of the ith building.
You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.

The skyline should be represented as a list of “key points” sorted by their x-coordinate in the form [[x1,y1],[x2,y2],…]. Each key point is the left endpoint of some horizontal segment in the skyline except the last point in the list, which always has a y-coordinate 0 and is used to mark the skyline’s termination where the rightmost building ends. Any ground between the leftmost and rightmost buildings should be part of the skyline’s contour.

Note: There must be no consecutive horizontal lines of equal height in the output skyline. For instance, […,[2 3],[4 5],[7 5],[11 5],[12 7],…] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: […,[2 3],[4 5],[12 7],…]

Example 1:

Input: buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
Output: [[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]

Explanation:
Figure A shows the buildings of the input.
Figure B shows the skyline formed by those buildings. The red points in figure B represent the key points in the output list.

Example 2:

Input: buildings = [[0,2,3],[2,5,3]]
Output: [[0,3],[5,0]]

Constraints:

  • 1 <= buildings.length <= 104
  • 0 <= lefti < righti <= 231 - 1
  • 1 <= heighti <= 231 - 1
  • buildings is sorted by lefti in non-decreasing order.

作业是抄的, 但是好歹抄明白了。

横坐标看做时间, 从左向右看, 扫过建筑的左侧时此建筑开始影响结果, 扫过建筑右侧时这种影响消失, 所以从这点来看,我们需要一个容器来保存当前能影响结果的建筑。再看结果中的那些点, 生成这些点就两种情况, 一种是扫描到当前建筑的左侧并且当前建筑的高度大于当前容器中的建筑的最大高度, 一种是扫描到当前建筑的右侧并且当前建筑的高度大于容器中除自己外其他建筑的最大高度。实际的实现中我们把一个建筑拆分成两个 pair, 一个是(left, -height), 一个是(right, height), 之所以要把 left 的 pair 中的 height 取负值, 一是为了处理过程中我们可以区分左右, 二是为了排序, 因为一栋建筑的左侧可能与另一栋建筑的右侧相连, 这种情况我们一定要先处理建筑的左侧, 也就是先让后面的建筑进入容器, 因为如果先处理建筑的右侧可能会导致丢失建筑右侧上的点。将 pairs 生成完之后我们对其进行排序, 之后我们建一个 binary heap 用于保存当前对结果有影响的建筑的高度, 遍历 pairs, 如果遇到 height < 0, 则将-height 加入到 binary heap 中, 意味着该建筑开始影响结果, 当遇到 height > 0 的,则将该 height 移出 binary heap, 意味着该建筑对结果的影响结束。设置一个变量保存当前的最高高度, 每次更新完 binary heap 后再将 binary heap 中的最大值取出, 如果此值与我们保存的变量值不一致, 说明最大高度有所变化, 需要生成轮廓上的点了



use std::collections::BinaryHeap;

impl Solution {
    pub fn get_skyline(buildings: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let mut heights = buildings.iter().fold(Vec::new(), |mut l, p| {
            l.push((p[0], -p[2]));
            l.push((p[1], p[2]));
            l
        });
        heights.sort_by(|p1, p2| {
            if p1.0 == p2.0 {
                return p1.1.cmp(&p2.1);
            }
            p1.0.cmp(&p2.0)
        });
        let mut heap = BinaryHeap::new();
        heap.push(0);
        let mut prev = 0;
        let mut ans = Vec::new();
        for (x, h) in heights {
            if h < 0 {
                heap.push(-h);
            } else {
                let mut l = Vec::new();
                loop {
                    let hh = heap.pop().unwrap();
                    if hh == h {
                        break;
                    }
                    l.push(hh);
                }
                for hh in l {
                    heap.push(hh);
                }
            }
            let &curr = heap.peek().unwrap();
            if curr != prev {
                ans.push(vec![x, curr]);
                prev = curr;
            }
        }
        ans
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值