218. The Skyline Problem

博客围绕建筑区间高度排序问题展开,给定[start, end, height]需按start排序以建立高度区间。处理过程中会遇到多种情况,如相同高度、高低楼嵌套等。最终使用TreeMap解决,时间复杂度为O(NlgN),还介绍了生成答案时的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


June-20-2019

这个题还是蛮好的啦~(台湾腔)这个人还是长得蛮像个傻逼的啦。。
最后的答案只需要[startX, height]就行了,而且第一个0的高度是不需要的= =

给的各种[start, end, height],需要按照start来排序,目的是从左到右建立各种高度的区间。
[3, 10, 4] [5, 10, 12]

[3, 12, 4]比如,从3开始有高度为4的建筑[3, 4],持续到12 => [12, -4]
第二个是[5, 10, 12], 从5开始变为12[5, 12],持续到10, [10, -12]
后面的负数代表到什么地方结束,所以上面的2个区间最后变为下面这种排序的list:
[3,4][5,12][10, -12][12, -4]

问题在于到10之后,我们知道5-10这段结束了,现在怎么回到3的高度。解决的方法是用类似于PQ的结构找到第二高的。

看起来很简单= = 然后各种case的处理比较麻烦,
比如2个建筑一样高[1,2,3][1,2,4],小的应该直接无视。
比如高的楼下面小的,应该被无视,第一个第二个小的要删除。要从PQ里找第二小的删除,那PQ就不行了

再比如一段很高的楼下面,有若干高度相等的小楼,所以不光要记得第二高的,还要记得第二高的有多少个= = 要找到最右边的才行

反正最后他妈的使用TreeMap了,<Height, Count> count = 当前高度有几段.

Time:
建 O(n) n = # of buildings
sort = O(NlgN)
build: put(), get(), remove() ... O(lgN) * N

最后O(NlgN)

class Solution {
    
    public class Interval {
        int start;
        int height;
        public Interval(int start, int height) {
            this.start = start;
            this.height = height;
        }
    }
    
    public List<List<Integer>> getSkyline(int[][] buildings) {
        List<List<Integer>> res = new ArrayList<>();
        if (buildings == null || buildings.length == 0) return res;
        
        List<Interval> intervals = new ArrayList<>(buildings.length * 2);
        
        for (int[] building : buildings) {
            intervals.add(new Interval(building[0], building[2]));
            intervals.add(new Interval(building[1], -building[2]));
        }
        
        Collections.sort(intervals, new Comparator<Interval>() {
            public int compare(Interval a, Interval b) {
                if (a.start != b.start) {
                    return Integer.compare(a.start, b.start);
                } else {
                    return Integer.compare(b.height, a.height);
                }
            }
        });
        
        TreeMap<Integer, Integer> map = new TreeMap<>();
        map.put(0, 1);
        int currentHeight = 0;
        
        for (Interval interval : intervals) {
            int start = interval.start;
            int height = interval.height;
            
            if (height > 0) {
                map.put(height, map.getOrDefault(height, 0) + 1);
            } else {
                int remain = map.get(-height) - 1;
                if (remain == 0) {
                    map.remove(-height);
                } else {
                    map.put(-height, remain);
                }
            }
            
            int tempHighest = map.lastKey();
            if (tempHighest == currentHeight) {
                // overriden, do nothing.
            } else {
                res.add(Arrays.asList(start, tempHighest));
                currentHeight = tempHighest;
            }
            
        }
        
        return res;
    }
}

Interval里高度,负数代表结束。
排序也说过了,按start;start一样,高的在前面,这样小的会被无视。
map(height, count)
treeMap.lastKey()找到最大的KEY,要记住key是sorted.
然后生成答案的时候

  • 找到start,入map,count++
  • 找到end,count --,如果等于0就删了。

tempHeight是每次选取MAP里最高的。
currentHeight其实是正在进行的高度。这俩一比较,一样就不动,不一样按新得的tempHeight来,因为最终答案不记录end,所以不一样其实就代表上一个高度的线结束了。

转载于:https://www.cnblogs.com/reboot329/p/11063577.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值