218 天际线问题

题目描述:
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)。
在这里插入图片描述
每个建筑物的几何信息用三元组 [Li,Ri,Hi] 表示,其中 Li 和 Ri 分别是第 i 座建筑物左右边缘的 x 坐标,Hi 是其高度。可以保证 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX 和 Ri - Li > 0。您可以假设所有建筑物都是在绝对平坦且高度为 0 的表面上的完美矩形。

例如,图A中所有建筑物的尺寸记录为:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] 。

输出是以 [ [x1,y1], [x2, y2], [x3, y3], … ] 格式的“关键点”(图B中的红点)的列表,它们唯一地定义了天际线。关键点是水平线段的左端点。请注意,最右侧建筑物的最后一个关键点仅用于标记天际线的终点,并始终为零高度。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。

例如,图B中的天际线应该表示为:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]。

说明:

任何输入列表中的建筑物数量保证在 [0, 10000] 范围内。
输入列表已经按左 x 坐标 Li 进行升序排列。
输出列表必须按 x 位排序。
输出天际线中不得有连续的相同高度的水平线。例如 […[2 3], [4 5], [7 5], [11 5], [12 7]…] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[…[2 3], [4 5], [12 7], …]

方法1:
主要思路:
(1)先使用multiset<pair<int,int>> points 来统计所有的建筑的左右两个顶点,并把左边的顶点的高度置为负数,便于区分(同一建筑的左右点)和排序(两个建筑,右边建筑的左顶点和左边建筑的右顶点相同时),这样将所有的顶点存入到multiset中,同时进行了排序;
(2)从头扫描multiset,使用辅助数组heights来统计当前正在统计的范围内的各个建筑的高度,扫描过程中,若当前高度数负数,则将高度插入到heights,若是正数,则从heights中删除该高度(注意,为了只删除重复高度中的一个,需要先使用find函数找出该高度对应的一个迭代器,来实现删除一个重复的高度的目的),同时使用pre_max_height来统计之前出现过的最大高度;
(3)当新的最大的高度和之前的最大的高度不一致时,说明此时是一个关键点,将该关键点插入到结果中,并更新最高点;

class Solution {
public:
    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
        multiset<pair<int,int>> points;//统计每个建筑的左右顶点
        for(vector<int>& b:buildings){
            points.insert({b[0],-b[2]});//左顶点的高度使用对应的负数进行表示
            points.insert({b[1],b[2]});//右顶点的高度正常表示
        }
        vector<vector<int>>res;//存储结果
        int pre_max_height=0;//保存之前出现过的最高高度
        multiset<int> heights({0});//保存有效的建筑的高度,既相当于建筑的左顶点出现时,将高度压入到该数组中,建筑的右顶点出现时,减该高度从数组中删除
        for(auto& point:points){//遍历所有的建筑的左右顶点,这里已经自动进行了排序
        	//决定当前建筑刚出现(既建筑的左顶点出现,将对应的高度插入到高度数组中),还是建筑即将跳过(既建筑的右顶点出现,将对应的高度从高度数组中删除)
            if(point.second>0){
                heights.erase(heights.find(point.second));
            }
            else{
                heights.insert(-point.second);
            }
            int cur_max_height=*heights.rbegin();//获得当前的高度数组中的最大的高度
            if(pre_max_height!=cur_max_height){//判断当前的最大的高度和之前的最大的高度是否是同一个高度,决定是否是新的关键点
                pre_max_height=cur_max_height;
                res.push_back({point.first,pre_max_height});//关键点使用当前点的横坐标和当前的最大的高度组成
            }
        }
        return res;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值