首页 > 试题广场 >

大楼轮廓问题

[编程题]大楼轮廓问题
  • 热度指数:729 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个的矩阵matrix,对于每一个长度为3的小数组arr,都表示一个大楼的三个数据。arr[0]表示大楼的左边界,arr[1]表示大楼的右边界,arr[2]表示大楼的高度(一定大于0)。每座大楼的地基都在X轴上,大楼之间可能会有重叠,请返回整体的轮廓线数组
[要求]
时间复杂度为

输入描述:
第一行一个整数N,表示大楼的数量。

接下来N行,每个三个整数,表示第i个大楼的信息


输出描述:
输出若干行,每行有3个整数,表示最终的轮廓线。
示例1

输入

8
2 5 6
1 7 4
4 6 7
3 6 5
10 13 2
9 11 3
12 14 4
10 12 5

输出

1 2 4
2 4 6
4 6 7
6 7 4
9 10 3
10 12 5
12 14 4

说明

给出的楼房信息以及最后的轮廓线如下图所示





备注:

为了描述所有建筑构建的轮廓线,我们需要求得每个坐标点上面的最大高度。每个大楼构建两个关键点,信息体结构如下:
  1. 坐标
  2. 是否是加入一个高度
  3. 大楼高度
于是对于某个大楼[x,y,h],我们可以得到两个关键点:(1) 大楼的起始坐标x、当前坐标是加入高度、高度为h;(2) 大楼的结束坐标y、当前坐标是删除高度、高度为h。于是n栋大楼可以构建2n个关键点来描述。按大楼的起始坐标进行排序(如果坐标相同,将加入高度的关键点排在前面,防止有“线状”大楼的存在)。
建立两个有序表,一个用于统计高度的频数mapHeightTimes,另一个用于记录某一位置的最大高度mapXvalueHeight。然后开始遍历排完序后的关键点,对一个关键点,我们有如下的两个操作:(1) 遇到增加高度的关键点就增加高度频数,否则减少高度频数;(2) 通过mapHeightTimes得到迄今为止的最大高度,它就是当前位置的最大高度(如果当前遍历到的是删除高度的关键点,就会终结这个高度的大楼对当前坐标点最大高度的影响,删除这个高度之后,高度频数表中的最大高度一定是当前坐标点的最大高度)。需要注意的是,在进行遍历的过程中,我们还需要保存好前一个高度,这样才能够描述出轮廓线的线段。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.TreeMap;
import java.util.Map.Entry;

class Node {
    public int x;
    public boolean isAdd;
    public int height;
    public Node(int x, boolean isAdd, int height) {
        this.x = x;
        this.isAdd = isAdd;
        this.height = height;
    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        Node[] buildings = new Node[2 * n];
        Node node;
        for(int i = 0; i < n; i++){
            String[] params = br.readLine().split(" ");
            node = new Node(Integer.parseInt(params[0]), true, Integer.parseInt(params[2]));
            buildings[i] = node;
            node = new Node(Integer.parseInt(params[1]), false, Integer.parseInt(params[2]));
            buildings[i + n] = node;
        }
        Arrays.sort(buildings, new Comparator<Node>() {
            @Override
            public int compare(Node node1, Node node2) {
                return node1.x != node2.x? node1.x - node2.x: node1.isAdd? -1: 1;
            }
        });
        TreeMap<Integer, Integer> mapHeightTimes = new TreeMap<>();
        TreeMap<Integer, Integer> mapXvalueHeight = new TreeMap<>();
        for(int i = 0; i < 2*n; i++){
            if(buildings[i].isAdd){
                mapHeightTimes.put(buildings[i].height, mapHeightTimes.getOrDefault(buildings[i].height, 0) + 1);
            }else{
                if(mapHeightTimes.get(buildings[i].height) == 1){
                    mapHeightTimes.remove(buildings[i].height);
                }else{
                    mapHeightTimes.put(buildings[i].height, mapHeightTimes.get(buildings[i].height) - 1);
                }
            }
            if(mapHeightTimes.isEmpty()){
                mapXvalueHeight.put(buildings[i].x, 0);    // 没有高度了,当前坐标x的最大高度为0
            }else{
                mapXvalueHeight.put(buildings[i].x, mapHeightTimes.lastKey());    // 否则是加入过的最大高度
            }
        }
        int preX = 0, preHeight = 0;
        for(Entry<Integer, Integer> entry: mapXvalueHeight.entrySet()) {
            // 当前位置及其最大高度
            int curX = entry.getKey();
            int curHeight = entry.getValue();
            if(curHeight != preHeight){
                // 高度改变时更新轮廓线
                if(preHeight != 0) System.out.println(preX + " " + curX + " " + preHeight);
                preX = curX;
                preHeight = curHeight;
            }
        }
    }
}

发表于 2021-12-02 16:01:18 回复(0)

问题信息

上传者:小小
难度:
1条回答 3643浏览

热门推荐

通过挑战的用户

查看代码