天际线问题

题目描述

城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图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], …]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/the-skyline-problem
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

求解 n 栋楼的天际线:
1、如果 n = 0:返回一个空列表。
2、如果 n = 1:返回一栋楼的天际线(左上角和右下角的坐标)。
3、leftSkyline = 求解前 n/2 栋楼的天际线。
4、rightSkyline = 求解后 n/2 栋楼的天际线。
5、合并 leftSkyline 和 rightSkyline。
在合并左右两个子天际线时,用三个整数变量 leftY,rightY 和 currY 分别记录 左天际线的高度、 右天际线的高度和在此之前合并的天际线的最大高度。每次选取x坐标最小的点,比较左右天际线高度取最高,再与currY比较,如果和currY相同,说明此时点的高度是小于等于前一个点的高度的,所以舍去当前点;否则更新currY,并记录当前点。

代码(c++)

class Solution {
public:
    vector<vector<int> > mergeSkyline(vector<vector<int> >& buildings,int s,int e){
        vector<vector<int> > res;
        if(s>e) return res;
        if(s==e){
            vector<int> point;
            point.push_back(buildings[s][0]);
            point.push_back(buildings[s][2]);
            res.push_back(point);
            point.clear();
            point.push_back(buildings[s][1]);
            point.push_back(0);
            res.push_back(point);
            return res;
        }
        vector<vector<int> > leftPart=mergeSkyline(buildings,s,(e-s)/2+s);
        vector<vector<int> > rightPart=mergeSkyline(buildings,(e-s)/2+s+1,e);
        return merge(leftPart,rightPart);
    }
    vector<vector<int> > merge(vector<vector<int> > &leftPart,vector<vector<int> > &rightPart){
        int pL=0,pR=0;
        int nL=leftPart.size(),nR=rightPart.size();
        int leftH=0,rightH=0,curH=0,maxH=0;
        int x=0;
        vector<vector<int> > res;
        while((pL<nL)&&(pR<nR)){
            if(leftPart[pL][0]<rightPart[pR][0]){
                x=leftPart[pL][0];
                leftH=leftPart[pL][1];
                pL+=1;
            }
            else{
                x=rightPart[pR][0];
                rightH=rightPart[pR][1];
                pR+=1;
            }
            maxH=max(leftH,rightH);
            if(curH!=maxH){
                updatePoint(res,x,maxH);
                curH=maxH;
            }
        }
        while(pL<nL){
            x=leftPart[pL][0];
            leftH=leftPart[pL][1];
            pL+=1;
            if(curH!=leftH){
                updatePoint(res,x,leftH);
                curH=leftH;
            }
        }
        while(pR<nR){
            x=rightPart[pR][0];
            rightH=rightPart[pR][1];
            pR+=1;
            if(curH!=rightH){
                updatePoint(res,x,rightH);
                curH=rightH;
            }
        }
        return res;
    }
    void updatePoint(vector<vector<int> > &res,int x,int y){
        if(res.size()==0||res[res.size()-1][0]!=x){
            vector<int> point;
            point.push_back(x);
            point.push_back(y);
            res.push_back(point);
        }
        else{
            res[res.size()-1][1]=y;
        }
    }
    vector<vector<int> > getSkyline(vector<vector<int> >& buildings) {
        return mergeSkyline(buildings,0,buildings.size()-1);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值