multiset+pair 218. 天际线问题

本文介绍了如何使用multiset和pair来解决218.天际线问题,通过堆排序性质找到最大高度,遍历建筑物端点,动态维护天际线并避免连续相同高度的水平线。
摘要由CSDN通过智能技术生成

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], …]

扫描线法
用multiset的堆排序性质,可以得到保存高度中的最大高度;
遇到新方块左端时加入其高度,遇到方块右侧时,删除该高度;

(1)vector<pair<int,int>> height 用于保存左右端点,为便于区分,左端点保存为负数;
(2)遍历building,把左右端点保存在height中,根据x轴排序height数组;
(3)遍历height,
遇到高度为负的即为左端点,该高度加入m,此时得到m中的最大高度cur,若cur!=pre,说明高度发生变化,将该高度与左边保存至res;
遇到高度为正的即为右端点,此时删除该高度(multiset.erase若传入迭代器,则只删除该位置,而find函数返回指向该数的迭代器,可实现只删除一个的操作),再获得当前的最大高度,若高度与前一个不同,则保存至res;

注意点
(1)m需事先加入0,以获得高度为0的点;
(2)multiset的删除要用find找到迭代器,不然会全部删掉;
(3)multiset的尾部rbegin()为最大值。

class Solution {
public:
    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
        vector<pair<int,int>> height;
        vector<vector<int>> res;
        multiset<int> m;  //有序性,最小的在最前面

        for(auto t:buildings){
            height.push_back({t[0],-t[2]});
            height.push_back({t[1],t[2]});
        }
        sort(height.begin(),height.end());  //按左端点排序;


        //
        int cur=0;  //当前最大高度
        int pre=0;  //前一个的最大高度
        m.insert(0); //0先入队,防止第一个方块没了之后,m中没元素
        //有了0,就可以得到一块结束后的0高度
        for(auto t:height){
            if(t.second<0) m.insert(-t.second);  //左端点,高度入队
            else m.erase(m.find(t.second));  //遇到右端点,则将该高度删除
            //找到最大的高度
            cur=*m.rbegin();  //最后一个元素,*为获得该值
            if(cur!=pre)    //后一个高度不等于前一个高度
            {
                res.push_back({t.first,cur});
                pre=cur;
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值