LintCode 131: The Skyline Problem (基于Heap的难题!)

本文深入探讨了天际线问题的解决策略,通过使用multiset和Node结构来处理建筑物轮廓的提取,确保了不同高度建筑物的正确排序和轮廓的连续性。文章详细解释了两种解法,包括如何在遍历过程中更新最大高度并记录轮廓变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

131. The Skyline Problem

中文English

Given N buildings in a x-axis,each building is a rectangle and can be represented by a triple (start, end, height),where start is the start position on x-axis, end is the end position on x-axis and height is the height of the building. Buildings may overlap if you see them from far away,find the outline of them。

An outline can be represented by a triple, (start, end, height), where start is the start position on x-axis of the outline, end is the end position on x-axis and height is the height of the outline.

Example 1

Input:
[
    [1, 3, 3],
    [2, 4, 4],
    [5, 6, 1]
]
Output:
[
    [1, 2, 3],
    [2, 4, 4],
    [5, 6, 1]
]
Explanation:
The buildings are look like this in the picture. The yellow part is buildings.

图片

Example 2

Input:
[
    [1, 4, 3],
    [6, 9, 5]
]
Output:
[
    [1, 4, 3],
    [6, 9, 5]
]
Explanation:
The buildings are look like this in the picture. The yellow part is buildings.

图片

Notice

Please merge the adjacent outlines if they have the same height and make sure different outlines cant overlap on x-axis.

解法1:这题不容易。思路参考自网上。注意这题一定只要比较每个building的开始时间,不能把开始时间和结束时间混在一起。

1) 用multiset(相当于最大堆),存储buildings的高度。
2) 遍历buildings,每次当building的起始位置时进堆,结束位置时出堆。
3) 当本次heap的最大值与上次记录heap的最大值不一致(不管是变大还是变小)时,检查上次heap记录的最大值的高度和时间,若都非0,则记录{preTime, curTime, preHeight},同时更新curTime, preHeight, preTime。
4) multiset一定要先插入一个0,不然堆可能为空。
5) buildings排序有讲究:
    a) if two time are the same, but different time type, the starting time is ahead of ending time
    b) if two time are the same, and are both starting time, then higher building first
    c) if two time are the same, and are both ending time, then lower building first
    d) if two time are different, smaller time first

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) {
        vector<pair<int, int>> h, record;
        multiset<int> m;
        int pre = 0, cur = 0;

        for (auto &a : buildings) {
            h.push_back({a[0], -a[2]});
            h.push_back({a[1], a[2]});
        }

        //sorting, 
        //1) if two time are the same, but different time type, the starting time is ahead of ending time
        //2) if two time are the same, and are both starting time, then higher building first
        //3) if two time are the same, and are both ending time, then lower building first
        //4) if two time are different, smaller time first
        sort(h.begin(), h.end());
        m.insert(0);

        for (auto &a : h) {
            if (a.second < 0) m.insert(-a.second);  //only when it is beginning border, insert the border
            else m.erase(m.find(a.second)); //remove the ending border
            cur = *m.rbegin(); //the highest one in multiset
            if (cur != pre) {
                record.push_back({a.first, cur});
                pre = cur;
            }
        }

        vector<vector<int>> res;
        int n = record.size();

        for (int i = 1; i < n; ++i) {
            if (record[i - 1].second > 0)
                res.push_back({record[i - 1].first, record[i].first, record[i - 1].second});
        }
        return res;
    }
};

 

 

解法2:类似解法1,不过还是用中规中矩的Node结构(time, type和height)来做。

代码如下:
 

struct Node {
    int time;
    int type; // 1: start, 2: end
    int height;
    Node(int tm = 0, int tp = 0, int ht = 0) : time(tm), type(tp), height(ht) {}
    
    //sorting, 
    //1) if two time are the same, but different time type, the starting time is ahead of ending time
    //2) if two time are the same, and are both starting time, then higher building first
    //3) if two time are the same, and are both ending time, then lower building first
    //4) if two time are different, smaller time first
    bool operator < (const Node & n) {
        if (this->time == n.time) {
            if (this->type != n.type) {
                return this->type == 1; 
            } else {
                return (this->type == 1) ? this->height >= n.height : this->height < n.height;
            } 
        } else {
            return this->time < n.time;
        }
    }
};

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) {
        vector<Node> heights;
        
        multiset<int> m;
        int preHeight = 0, curHeight = 0;
        int preTime = 0, curTime = 0;
        vector<vector<int>> res;

        for (auto &building : buildings) {
            heights.push_back(Node(building[0], 1, building[2]));
            heights.push_back(Node(building[1], 2, building[2]));
        }

        sort(heights.begin(), heights.end());
        m.insert(0);  // in case multiset is empty

        for (auto &height : heights) {

            if (height.type == 1) m.insert(height.height); //if starting border, insert the height into multiset
            else m.erase(m.find(height.height)); //if ending border, erase one of the height from multiset

            curHeight = *m.rbegin(); //the highest height in multiset
            
            //each time if the current highest height in multiset is different from previous highest height, and preTime && preHeight > 0, record the segment.
            if (curHeight != preHeight) {
                if (preTime != 0 && preHeight != 0) res.push_back({preTime, height.time, preHeight});
                curTime = height.time;
                preHeight = curHeight;
                preTime = curTime;
            }
        }

        return res;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值