218. The Skyline Problem

问题:

给定一个数组,表示楼的宽+高[x1,x2,h],求所形成的城市轮廓。

Input
[[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
Output
[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]

Input
[[1,2,1],[1,2,2],[1,2,3]]
Output
[[1,3],[2,0]]

  

解法:

解法一:FenwickTree

利用特点:通常的FenwickTree(如下图)所求为,前0~i个元素的和。

前面的值 贡献构成->后面的值

 

 

 

这里,我们利用后缀构造,求第i~∞个元素中的最大值。

后面的值(x2) 贡献构成->前面的值(x1~x2之间的值)。

  • index:x2
  • value:max(h)

 

 例如,上图中

  • tree[2]:表示node[2]的最大值和node[3]的最大值,再求最大值。
  • tree[8]:表示node[8],node[9]...node[15]的最大值。

在本问题中,我们每读入一个楼的信息(遍历到x1的位置时),[x1,x2,h] 将上述的数据结构 update(x2, h)

更新node[x2]上的值,同时更新<x2的idx上的各个node的值。

  • 当我们求,x0的最大值时,还未录入h,x0累计>x0的各个值。由于刚开始所以都为0
  • 当我们求,x1.5的最大值时,已录入h,x1.5累计>x1.5的各个值,包含x2。因此为h
  • 当我们求,x3的最大值时,x3累计>x3的各个值,不包含x2,因此h不能参与计算。
 
代码参考:
 1 class FenwickTree {//Suffix sum tree (Normal is Preffix sum tree)
 2 public:
 3     FenwickTree(int n):tree(n+1, 0) {}
 4     void update(int i, int delta) {
 5         i++;
 6         while(i>=1){
 7             tree[i]=max(tree[i], delta);
 8             i -= lowbit(i);
 9         }
10     }
11     int getSuMax(int i) {//max(i~infinite)
12         int maxres = 0;
13         i++;
14         while(i<tree.size()){
15             maxres=max(tree[i], maxres);
16             i += lowbit(i);
17         }
18         return maxres;
19     }
20     
21 private:
22     vector<int> tree;
23     int lowbit(int x) {
24         return x&(-x);
25     }
26 };
27 
28 class Event {
29 public:
30     int x;//坐标x
31     int h;//高度
32     int i;//楼号
33 };
34 
35 class Solution {
36 public:
37     static bool cmp(Event a, Event b){
38         return (a.x == b.x)? a.h > b.h : a.x < b.x;//x坐标相同的情况下,高的排前面(防止二重输出)
39     }
40     vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
41         set<vector<int>> res;
42         vector<Event> eventlist;
43         map<int,int> posX;//映射x2排序后的index
44         int i=0, j=0;
45         for(vector<int> b:buildings){
46             eventlist.push_back({b[0], b[2], j});//楼开始
47             eventlist.push_back({b[1], -b[2], j++});//楼结束
48         }
49         sort(eventlist.begin(), eventlist.end(), cmp);
50         for(int i=0; i<eventlist.size(); i++){
51             posX.insert({eventlist[i].x, i});
52         }
53         FenwickTree ftree(eventlist.size());
54         for(Event e:eventlist){
55             int maxh = ftree.getSuMax(posX[e.x]);//FenwickTree query
56             if(e.h > 0) {
57                 int x2 = buildings[e.i][1];
58                 ftree.update(posX[x2], e.h);//FenwickTree update
59                 if(abs(e.h) > maxh) res.insert({e.x, e.h});
60             } else {
61                 int maxh2 = ftree.getSuMax(posX[e.x]+1);
62                 if(abs(e.h) > maxh2) res.insert({e.x, maxh2});
63             }
64         }
65         vector<vector<int>> res1(res.begin(), res.end());//去重
66         return res1;
67     }
68 };

 

解法二:multiset

【参考 huahua:https://zxi.mytechroad.com/blog/tree/leetcode-218-the-skyline-problem/

利用multiset的特性:

  • insert形成排好序的set,最小值begin(),最大值rbegin()
  • 允许重复元素

我们需要用到的操作:

  • 插入一个数,insert(val) 
  • 删除某个值,erase(find(val))
  • 最大值,*rbegin()
  • 最小值,*begin()

插入一个数,删除一个数:时间复杂度:O(logn)

⚠️ 注意:

由于避免向结果插入多余不必要的节点,我们使用eventlist排序时,

  1. 首先按照x坐标排序,其次若x相同,则大楼 entering事件 先于 leave事件 处理。
  2. 若都是entering事件,那么更高的楼先处理。

因此有:

1     static bool cmp(Event a, Event b){
2         return (a.x == b.x)? a.h > b.h : a.x < b.x;
3     }
4 
5     sort(eventlist.begin(), eventlist.end(), cmp);

理由如下2图:

 

代码参考:

 1 class Event {
 2 public:
 3     int x;
 4     int h;
 5 };
 6 
 7 class Solution {
 8 public:
 9     static bool cmp(Event a, Event b){
10         return (a.x == b.x)? a.h > b.h : a.x < b.x;
11     }
12     vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
13         vector<vector<int>> res;
14         vector<Event> eventlist;
15         for(vector<int> b:buildings){
16             eventlist.push_back({b[0], b[2]});
17             eventlist.push_back({b[1], -b[2]});
18         }
19         sort(eventlist.begin(), eventlist.end(), cmp);
20         for(Event e:eventlist){
21             bool entering = e.h>=0;
22             int newh = abs(e.h);
23             int maxh;
24             if(entering){
25                 maxh = getMaxHeight();
26                 if(newh>maxh){
27                     res.push_back({e.x, newh});
28                 }
29                 height.insert(newh);
30             }else{
31                 height.erase(height.find(newh));
32                 maxh = getMaxHeight();
33                 if(maxh<newh){
34                     res.push_back({e.x, maxh});
35                 }
36             }
37         }
38         return res;
39     }
40 private:
41     multiset<int> height;
42     int getMaxHeight(){
43         if(height.size()==0) return 0;
44         else return *height.rbegin();
45     }
46 };

 

posted @ 2020-08-04 19:58  habibah_chang  阅读(111)  评论(0编辑  收藏  举报