【Lintcode】131. The Skyline Problem

题目地址:

https://www.lintcode.com/problem/131/description

给定若干矩形大楼的左右边界坐标以及其高度,要求返回大楼的轮廓线。其轮廓线指,从左到右若干不相交的区间,每段区间的大楼高度相同,也就是说,要返回三元组的集合。高度为 0 0 0的区间不必返回,并且相邻区间的大楼高度必须不一样。

思路是扫描线 + TreeMap。先将所有边界点按照从左到右排序,若下标相同则按左边界优先的顺序排序(左边界优先的目的是,如果有新的楼被扫描到,它的高度应该能盖住将要出去的左边的楼的右边界。例如考虑 [ [ 1 , 3 , 3 ] , [ 3 , 4 , 3 ] ] [[1, 3, 3], [3, 4, 3]] [[1,3,3],[3,4,3]],如果右边界优先的话,在第一个楼的右边界出去时,TreeMap为空,此时会误以为出现了高度为 0 0 0的一段区间,但是第二个楼事实上可以接上去)。接着开一个TreeMap,key存高度,value存各自高度当前有多少个楼。接着从小到大遍历边界点的集合,为了求出每段区间的左右端点,可以维护两个变量,分别是上次边界点的下标和高度。而TreeMap的lastKey负责求高度。接着遍历所有的边界,如果其是左边界,则加入TreeMap进行计数,此时TreeMap的lastkey表示当前位置最高楼的高度;如果其是右边界,则从TreeMap中计数减 1 1 1,如果计数减到了 0 0 0则在TreeMap中删除。如果当前高度不等于之前的高度,说明有可能产生了一段要加入答案的区间,该区间的高度是之前的高度,区间端点是两个下标;如果之前的高度大于 0 0 0并且下标不同,才需要加入答案;接着更新下标和高度。代码如下:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;

public class Solution {
    
    
    class Pair {
    
    
        int pos, h, stat;
        
        public Pair(int pos, int h, int stat) {
    
    
            this.pos = pos;
            this.h = h;
            this.stat = stat;
        }
    }
    
    /**
     * @param buildings: A list of lists of integers
     * @return: Find the outline of those buildings
     */
    public List<List<Integer>> buildingOutline(int[][] buildings) {
    
    
        // write your code here
        Pair[] pairs = new Pair[buildings.length << 1];
        // 将左右端点及其高度作为整体存起来
        for (int i = 0; i < buildings.length; i++) {
    
    
            int[] b = buildings[i];
            pairs[i * 2] = new Pair(b[0], b[2], 0);
            pairs[i * 2 + 1] = new Pair(b[1], b[2], 1);
        }
        
        // 按下标排序;下标相同则左边界优先
        Arrays.sort(pairs, (p1, p2) -> p1.pos != p2.pos ? Integer.compare(p1.pos, p2.pos) : Integer.compare(p1.stat, p2.stat));
        
        TreeMap<Integer, Integer> hMap = new TreeMap<>();
        int preHeight = 0, prePos = 0;
        List<List<Integer>> res = new ArrayList<>();
        for (Pair pair : pairs) {
    
    
            if (pair.stat == 0) {
    
    
                hMap.put(pair.h, hMap.getOrDefault(pair.h, 0) + 1);
            } else {
    
    
                hMap.put(pair.h, hMap.get(pair.h) - 1);
                if (hMap.get(pair.h) == 0) {
    
    
                    hMap.remove(pair.h);
                }
            }
            
            int curHeight = hMap.isEmpty() ? 0 : hMap.lastKey();
            if (preHeight != curHeight) {
    
    
                if (pair.pos != prePos && preHeight != 0) {
    
    
                    res.add(Arrays.asList(prePos, pair.pos, preHeight));
                }
                
                prePos = pair.pos;
                preHeight = curHeight;
            }
        }
        
        return res;
    }
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn) n n n为大楼数量,空间 O ( n ) O(n) O(n)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/121210064