LeetCode解析------218.天际线问题-树状数组

题目:

城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)。
在这里插入图片描述
在这里插入图片描述

每个建筑物的几何信息用三元组 [Li,Ri,Hi] 表示,其中 Li 和 Ri 分别是第 i 座建筑物左右边缘的 x 坐标,Hi 是其高度。可以保证 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX 和 Ri - Li > 0。您可以假设所有建筑物都是在绝对平坦且高度为 0 的表面上的完美矩形。

示例 1:

例如,图A中所有建筑物的尺寸记录为:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] 。
输出是以 [ [x1,y1], [x2, y2], [x3, y3], … ]格式的“关键点”(图B中的红点)的列表,它们唯一地定义了天际线。关键点是水平线段的左端点。请注意,最右侧建筑物的最后一个关键点仅用于标记天际线的终点,并始终为零高度。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
例如,图B中的天际线应该表示为:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8],[24, 0] ]。

说明:

任何输入列表中的建筑物数量保证在 [0, 10000] 范围内。 输入列表已经按左 x 坐标 Li 进行升序排列。 输出列表必须按 x 位排序。 输出天际线中不得有连续的相同高度的水平线。例如 […[2 3], [4 5], [7 5], [11 5], [12 7]…] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[…[2 3], [4 5], [12 7], …]

简单介绍:
题目:天际线问题
题目难度:困难
使用语言:JAVA。
这道题来自leetcode题库的树状数组标签。

解题思路:
首先看题、分析题意,我们可以明确1个关键点:
1.记录拐点,保存当前区间最高建筑物的左边坐标。
既然,我们已经分析出来题目的关键任务了,下面我们就可以开始思考实现了。
我们采用算法与数据结构的思路来剖析一下这题,

数据结构:
要实现对数据的操作,我们要先明确存储数据的数据结构。
该题的数据结构的作用:
1.points:调整顺序后的建筑物坐标,按x坐标从小到大。
-----x相同的情况:------
a.左坐标在右坐标前面
b.同为左坐标,高的在前
c.同为右坐标,高的在后
2.results:保存结果

算法:
既然明确了我们的数据结构,我们就可以开始我们的算法分析了。
1.自定义排序规则,如上面数据结构所描述的
2.自定义一个TreeMap,从大到小排序
3.遍历points,左边坐标出现则相应高度加1,右边坐标出现则相应高度减1。
高度变化,则加入results。

代码部分:

import java.util.*;

public class Solution {
    public List<List<Integer>> getSkyline(int [][]buildings){
        List<List<Integer>> points=new ArrayList<>();//参与运算
        List<List<Integer>> results=new ArrayList<>();//结果
       // int n=buildings.length;
        //查找左上角右上角坐标,左上角坐标保存为负数
        for(int []b:buildings){
            List<Integer> p1=new ArrayList<>();
            p1.add(b[0]);
            p1.add(-b[2]);
            points.add(p1);

            List<Integer> p2=new ArrayList<>();
            p2.add(b[1]);
            p2.add(b[2]);
            points.add(p2);
        }
         //对坐标排序,利用自定义比较规则
        Collections.sort(points, new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> p1, List<Integer> p2) {
                int x1=p1.get(0);
                int y1=p1.get(1);
                int x2=p2.get(0);
                int y2=p2.get(1);
                if(x1!=x2){
                    return x1-x2;//从小到大排序
                } else {
                    return y1-y2;//左坐标从大到小,右坐标从小到大
                }
            }
        });

        TreeMap<Integer,Integer> treeMap=new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;//依次找到最大的
            }
        });
        treeMap.put(0,1);//初始设置最大堆
        int preMax=0;//目前最大高度

        for(List<Integer> p:points){//逐个查找拐点
            int x=p.get(0);
            int y=p.get(1);
            if(y<0){
                Integer v=treeMap.get(-y);//高度调整
                if(v==null){
                    treeMap.put(-y,1);
                } else {
                    treeMap.put(-y,v+1);
                }
            }else {
                Integer v= treeMap.get(y);
                if(v==1){
                    treeMap.remove(y);
                }else{
                    treeMap.put(y,v-1);
                }
            }

            int curMax=treeMap.firstKey();
            if(curMax!=preMax){//高度变化,则添加拐点
                List<Integer> temp=new ArrayList<>();
                temp.add(x);
                temp.add(curMax);
                results.add(temp);
                preMax=curMax;
            }
        }

        return results;


    }
}

在这里插入图片描述

结语:
晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值