持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情
218. 天际线问题 - 力扣(LeetCode)
城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [lefti, righti, heighti] 表示:
- lefti 是第 i 座建筑物左边缘的 x 坐标。
- righti 是第 i 座建筑物右边缘的 x 坐标。
- heighti 是第 i 座建筑物的高度。
你可以假设所有的建筑都是完美的长方形,在高度为 0 的绝对平坦的表面上。
天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...] ,并按 x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y 坐标始终为 0 ,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
示例 1:
输入:buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
输出:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
解释:
图 A 显示输入的所有建筑物的位置和高度,
图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。
示例 2:
输入:buildings = [[0,2,3],[2,5,3]]
输出:[[0,3],[5,0]]
提示:
- 1 <= buildings.length <= 10^4
- 0 <= lefti < righti <= 2^31 - 1
- 1 <= heighti <= 2^31 - 1
- buildings 按 lefti 非递减排序
问题解析
这题的要求很简单,就是让我们先找出每个位置最高的高度,然后输出所有高度变化处的点。
主要难点就在于怎么知道每个位置的最高高度。
- 我们可以把每个房子,看做给区间lefti到righti处都赋值为heighti ,若一个位置被重复赋值,我们取最大值。
- 这一点我们可以用区间赋值和单点查询的线段树来做到。
- 赋值完后,对于每个位置i,我们在线段树上查询出他的最大值。把结果存在数组里。
- 然后遍历一遍数组,对于每个变化的位置,我们把它和当前的高度都记录下来。
要注意的是:
- 因为left和right过大,但n的总数很小,所以我们要对left和right离散化。
- 由于线段树的特性,对于一个房子,它实际赋值的区间应该为left和right-1。
AC代码
typedef long long ll;
const int N=3e4+50;
class Solution {
public:
ll f[4*N],lz[4*N],a[N];
void push_down(int k)
{
if(lz[k])
{
lz[k+k]=max(lz[k+k],lz[k]);
lz[k+k+1]=max(lz[k+k+1],lz[k]);
f[k+k]=max(f[k+k],lz[k]);
f[k+k+1]=max(f[k+k+1],lz[k]);
lz[k]=0;
}
}
void revise(int k,int l,int r,int x,int y,ll z)
{
if(l==x&&r==y)
{
lz[k]=max(lz[k],z);
f[k]=max(f[k],z);
return;
}
push_down(k);
int mid=(l+r)/2;
if(y<=mid)revise(k+k,l,mid,x,y,z);
else
if(x>mid)revise(k+k+1,mid+1,r,x,y,z);
else
{
revise(k+k,l,mid,x,mid,z);
revise(k+k+1,mid+1,r,mid+1,y,z);
}
}
int query(int k,int l,int r,int x)
{
if(l==r)return f[k];
push_down(k);
int mid=(l+r)/2;
if(x<=mid)return query(k+k,l,mid,x);
else return query(k+k+1,mid+1,r,x);
}
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
unordered_map<ll,int>mymap,mymap2;
vector<int>v;
for(auto i:buildings)
{
v.push_back(i[0]);
v.push_back(i[1]-1);
v.push_back(i[1]);
}
int cnt=0;
sort(v.begin(),v.end());
for(auto i:v)
{
if(!mymap.count(i))
{
mymap[i]=++cnt;
mymap2[cnt]=i;
}
}
for(auto &i:buildings)
{
revise(1,1,cnt,mymap[i[0]],mymap[i[1]-1],i[2]);
}
vector<int>ans(cnt+1);
for(int i=1;i<=cnt;i++)
{
ans[i]=query(1,1,cnt,i);
}
vector<vector<int>>res;
ll mx=0;
for(int i=0;i<=cnt;i++)
{
if(ans[i]!=mx)
{
mx=ans[i];
res.push_back({mymap2[i],ans[i]});
}
}
return res;
}
};