131. The Skyline Problem 矩形并问题

16 篇文章 0 订阅
12 篇文章 0 订阅

描述

水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用一个三元组表示 (start, end, height),分别代表其在x轴上的起点,终点和高度。大楼之间从远处看可能会重叠,求出 N 座大楼的外轮廓线。

外轮廓线的表示方法为若干三元组,每个三元组包含三个数字 (start, end, height),代表这段轮廓的起始位置,终止位置和高度。

请注意合并同样高度的相邻轮廓,不同的轮廓线在x轴上不能有重叠。

您在真实的面试中是否遇到过这个题?  是

样例

给出三座大楼:

[
  [1, 3, 3],
  [2, 4, 4],
  [5, 6, 1]
]

外轮廓线为:

[
  [1, 2, 3],
  [2, 4, 4],
  [5, 6, 1]
]

一开始没想明白怎么做,看题目像是矩形并集问题,一直在往线段树之类的方面想。后来看了别人的解题报告,发现是自己想偏了。

具体做法是把所有的线段的两个端点分别当成两个点保存起来,然后按x轴排序,保存时需要保存这个点是线段的起点还是终点。

接下来扫描所有点:若是起点,则往一个multiset当中插入一个当前线段的高,如果这个插入的高是目前set中的最大值,记录下left,如果不是最大值,不记录left,但是要往multiset插入当前的高。如果是终点,则在multiset中移除当前线段的高。此时观察被移除的高是否是multiset的最大值,如果不是最大值,证明当前的节点是被更高的楼覆盖了,如果是最大值,则说明当前的x就是right,保存left,right,height,存入答案数组。

大体的思路如上

然后就是这个题的各种细节很多,比如有重复点问题、当multiset为空时的处理。

重复点问题我的处理方案是非常小心的设计了排序函数,multiset为空时,有做特殊处理

具体看看代码吧,写的很冗长。

另:我看过别人的解题报告,有很多虽然思路一样但是质量很高很简洁的代码,值得学习

struct node{
    int x;
    int height;
    bool is_begin;
};

bool node_cmp(node a,node b)
{
    if(a.x==b.x)
    {
        if(a.is_begin&&b.is_begin)
            return a.height>b.height;
        else if(!a.is_begin&&!b.is_begin)
            return a.height<b.height;
		else
			return a.is_begin;
    }
    else
        return a.x<b.x;
}

class Solution {
public:
    vector<vector<int>> buildingOutline(vector<vector<int>> &buildings)
    {
        int i;
        vector<vector<int>>::const_iterator iter;
        vector<node> node_list;
        for(iter=buildings.cbegin();iter!=buildings.cend();++iter)
        {
            node temp;
            temp.x=(*iter)[0];
            temp.height=(*iter)[2];
            temp.is_begin=true;
            node_list.push_back(temp);
            temp.x=(*iter)[1];
            temp.height=(*iter)[2];
            temp.is_begin=false;
            node_list.push_back(temp);
        }
        sort(node_list.begin(),node_list.end(),node_cmp);
        multiset<int,greater<int>> height_set;
        vector<vector<int>> result;
        int left,right;
        for(i=0;i<node_list.size();++i)
        {
            node temp_node=node_list[i];
            if(height_set.empty())
            {
                left=temp_node.x;
                height_set.insert(temp_node.height);
            }
            else
            {
                if(temp_node.is_begin)
                {
                    int origen_max=(*height_set.begin());
                    if(temp_node.height>origen_max)
                    {
						height_set.insert(temp_node.height);
                        right=temp_node.x;
                        vector<int>temp;
                        temp.push_back(left);
                        temp.push_back(right);
                        temp.push_back(origen_max);
                        result.push_back(temp);
						left=temp_node.x;
                    }
					else
					{
						height_set.insert(temp_node.height);
					}
                }
                else
                {
                    int origen_max=(*height_set.begin());
                    multiset<int,less<int>>::iterator delete_iter=height_set.find(temp_node.height);
                    height_set.erase(delete_iter);
					if(height_set.empty())
					{
						vector<int>temp;
						right=temp_node.x;
                        temp.push_back(left);
                        temp.push_back(right);
                        temp.push_back(origen_max);
                        result.push_back(temp);
					}
                    else if(origen_max!=(*height_set.begin()))
                    {
						vector<int>temp;
						right=temp_node.x;
                        temp.push_back(left);
                        temp.push_back(right);
                        temp.push_back(origen_max);
                        result.push_back(temp);
                        left=temp_node.x;
                    }
                }
            }
        }
        return result;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值