218J. The Skyline Problem
https://leetcode.com/problems/the-skyline-problem/
重点部分: 1. 这个题一个最重要的观察是:keypoints按什么规则记录? 是每当当前的最高高度发生变化的时候(上升或者下降),记录keypoints. 2. 最重要的edge case: 有两个长方形的一边在同一个位置时。
一般思路: 1. 把每个长方形视为两个竖线。一个左竖线,一个右竖线。建立竖线数组[pos,height]。 2. 区分左右竖线的办法是,把高度分为正负。左竖线用负高度。 3. 把所有的竖线加入到竖线数组中进行排序。优先按竖线的位置排序,位置相同时,右竖线应当靠前。 4. 为什么是右竖线靠前呢?这是为了强行给两个无缝衔接的方块制造交叉。否则的话代码会将他们 识别为两个独立的方块,从而记录下错误的keypoints. 5. 我们从左到右扫描这些竖线。注意我们需要记录当前的最高高度。这样才能观察到最高高度的变化。 同时我们还需要一个机制,使得我们遇到右竖线的时候能退出它对应的左竖线,并更新最大高度。 6. 符合这个需求的数据结构,自然就有heap,和TreeMap. 7. 我们先用heap.左竖线无脑入堆,堆顶就是当下的 max高度. 当遇到右竖线的时候,从堆中删除右竖线对应的左竖线。 8. 如果堆顶的高度,和上一次循环的最大高度不一样,说明最大高度被更新了, 我们应当记录key point 并 更新上一次的最大高度。
class Solution {
public List<List<Integer>> getSkyline(int[][] buildings) {
List<int[]> heights = new ArrayList<>();
for(int[] rectangle : buildings){
int h = rectangle[2];
heights.add(new int[]{rectangle[0], - h});
heights.add(new int[]{rectangle[1], h});
}
heights.sort( (a,b) ->{
if( a[0]!=b[0] ){
return a[0] - b[0];
}
return a[1] - b[1];
});
List<List<Integer>> kps = new ArrayList<>(); // key points
PriorityQueue<Integer> heap = new PriorityQueue<>((a,b) -> b - a);
heap.offer(0);
int lastMax = 0;
for(int[] height : heights){
if(height[1] < 0){
heap.offer(-height[1]);
}else{
heap.remove(height[1]);
}
int curMax = heap.peek();
if(curMax != lastMax){
List<Integer> temp = new ArrayList<>();
temp.add(height[0]);
temp.add(curMax);
kps.add(temp);
lastMax = curMax;
}
}
return kps;
}
}
可以想想用TreeMap写,而且更快。只是更难处理edge case了。 PQ: 135 ms 47.6 MB TreeMap: 19 ms 42.6 MB
class Solution {
public List<List<Integer>> getSkyline(int[][] buildings) {
List<int[]> heights = new ArrayList<>();
for(int[] rectangle : buildings){
int h = rectangle[2];
heights.add(new int[]{rectangle[0], - h});
heights.add(new int[]{rectangle[1], h});
}
heights.sort( (a,b) ->{
if( a[0]!=b[0] ){
return a[0] - b[0];
}
return a[1] - b[1];
});
List<List<Integer>> kps = new ArrayList<>(); // key points
TreeMap<Integer, Integer> map = new TreeMap<>((a,b) -> b - a);
map.put(0,0);
int lastMax = 0;
for(int[] height : heights){
if(height[1] < 0){
map.put(-height[1], map.getOrDefault(-height[1],0) + 1 );
}else{
int number = map.getOrDefault(height[1],0);
if(number > 1){
map.put(height[1], number - 1 );
}else{
map.remove(height[1]);
}
}
int curMax = map.firstKey();
if(curMax != lastMax){
List<Integer> temp = new ArrayList<>();
temp.add(height[0]);
temp.add(curMax);
kps.add(temp);
lastMax = curMax;
}
}
return kps;
}
}
Last updated
Was this helpful?