sweep line-The Skyline Problem
2020-01-10 17:51:05
问题描述:
问题求解:
本题是经典的sweep line问题。
对于sweep line问题我们需要考虑的只有两点:
1. 延水平方向 / 时间方向 :时间队列 event queue,一般来说是一个优先队列;
2. 延垂直方向 :sweep line status,即当前的扫描线的状态,一般会将交点按照顺序排序;
对于本题来说,sweep line status可以使用一个multi set来进行维护,当然由于在Java中没有multi set,因此需要使用TreeMap来模拟。
event queue的当然是使用优先队列,问题是如何进行排序,这个才是本题的核心难点。
这里给出结论:
大方向是按照x轴排序,如果x轴相等那么按照height排序;
如果x轴相等,优先判断是否是左端点,如果是左端点,那么优先入队;
如果同时是右端点,那么需要反序入队,就是height小的反而需要排在前面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public List<List<Integer>> getSkyline( int [][] buildings) { List<List<Integer>> res = new ArrayList<>(); // 对于同x轴,优先将左端点入队列 // 如果同是右端点,则要反序,小的先入队列 // 其余按照正常的height顺序排列即可 PriorityQueue< int []> pq = new PriorityQueue<>( new Comparator< int []>(){ public int compare( int [] o1, int [] o2) { if (o1[0] == o2[0] && o1[2] != o2[2]) return o1[2] - o2[2]; if (o1[0] == o2[0] && o1[2] == 1 && o1[2] == o2[2]) return o1[1] - o2[1]; return o1[0] == o2[0] ? o2[1] - o1[1] : o1[0] - o2[0]; } }); TreeMap<Integer, Integer> map = new TreeMap<>(); for ( int [] b : buildings) { int s = b[0]; int e = b[1]; int h = b[2]; pq.add( new int []{s, h, 0}); pq.add( new int []{e, h, 1}); } while (!pq.isEmpty()) { int [] event = pq.poll(); int x = event [0]; int h = event [1]; int status = event [2]; int curr_max = map.size() == 0 ? 0 : map.lastKey(); if (status == 0) { if (h > curr_max) res.add(Arrays.asList(x, h)); map.put(h, map.getOrDefault(h, 0) + 1); } else { map.put(h, map. get (h) - 1); if (map. get (h) == 0) map.remove(h); curr_max = map.size() == 0 ? 0 : map.lastKey(); if (h > curr_max) res.add(Arrays.asList(x, curr_max)); } } return res; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步