Lintcode 131 Building Outline

今天在leetcode上面看到一道题shyline 与这道题一模一样,但是leetcode比较专业把数据的范围给了出来,而lintcode没有,但是我发现其实lintcode的X轴是在300000以内的,所以就不需要一条边一条边的扫描了,直接扫描每个坐标就好了。这样就完全能过了。


class Solution {
public:
    
    /**
     * @param buildings: A list of lists of integers
     * @return: Find the outline of those buildings
     */
    vector<vector<int> > buildingOutline(vector<vector<int> > &buildings) {
        // write your code here
        vector<vector<int> > res;
        const int size = 300000;
        int n = buildings.size();
        if(n==0) return res;
        sort(buildings.begin(),buildings.end());
        priority_queue<vector<int>> hp;
        
        int bp = 0,cur_h = -1,start = -1;
        vector<int> build = buildings[bp];
        for(int i=0;i<size;i++){
            while(!hp.empty()){
                if(hp.top()[2] < i ) hp.pop();//height overflow
                else break;
            }
            if(!hp.empty()){
                if(hp.top()[0] == cur_h) {
                    res.back()[1] = i;
                }
                else {
                    cur_h = hp.top()[0];
                    res.push_back({start,i,cur_h});
                }
            }
            while(bp<n && build[0] == i) {
                hp.push({build[2],build[0],build[1]});
                if(++bp < n) 
                    build = buildings[bp];
            }
            start = i;
        }
        return res;
    }
};


这道题确实挺纠结的,在Lintcode上过的也挺奇葩,有时候能过,有时候又过不了,但总体而言还是过了,写一下记录一下思路


刚开始想的是用堆将大楼从高到低开始找轮廓,但是每次大楼分裂,或者从前面找到结果时,需要把vector里面的元素右移,复杂度太高,自然是过不了,只能过到第17组数据


后来就改成了按坐标从左至右扫描大楼边的方式,并通过大堆记录当前楼的最高值,依次找出大楼轮廓。


将大楼的边按照进楼和出楼的方式存储,然后按照X坐标大小从小到大排列,并开始从左至右扫描edges,当遇到边edge是进楼时,则往堆中插入该栋大楼,

并扫描将堆顶元素中无效元素进行删除(该楼的右侧小于当前edge), 然后依次找到上次的edge与当前edge以及当前最大高度的大楼轮廓,如果上次的高度与本次高度一致则只需要延续上个edge的右侧。

struct HightCmp{
    bool operator()(vector<int> a,vector<int> b){
        return a[2]<b[2];
    }
};

class Solution {
public:
    
    /**
     * @param buildings: A list of lists of integers
     * @return: Find the outline of those buildings
     */
    vector<vector<int> > buildingOutline(vector<vector<int> > &buildings) {
        // write your code here
        vector<vector<int> > res;
        if(buildings.size()==0) return res;
        vector<vector<int>> edges;
        vector<int> edge(4,0);
        for(vector<int> bd : buildings){//n
            edge[0] = bd[0];edge[1] = bd[1];
            edge[2] = bd[2];edge[3] = 1;
            edges.push_back(edge);
            edge[0] = bd[1];edge[3] = 0;
            edges.push_back(edge);
        }
        sort(edges.begin(), edges.end());//n
        priority_queue<vector<int>,vector<vector<int>>,HightCmp> q;
        vector<int> bd(3,0),tb;
        int last = -1;
        for(vector<int> edg : edges){//n
            while(!q.empty()){//building unavailable logn
                if(edg[0] > q.top()[1]) q.pop();
                else break;
            }
            if(q.empty() || last == edg[0]){
                if(edg[3]){
                    bd = {edg[0],edg[1],edg[2]};
                    q.push(bd);
                }
                last = edg[0];
                continue;
            }
            tb = q.top();
            if(res.empty() || res.back()[2] != tb[2]){
                bd = {last,edg[0],tb[2]};
                res.push_back(bd);
            }else{
                res.back()[1] = edg[0];
            }
            if(edg[3]){
                bd = {edg[0],edg[1],edg[2]};
                if(bd[1] > tb[1] || tb[2] < bd[2])q.push(bd);
            }
            last = edg[0];
        }
        return res;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值