热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

LeetCode0218TheSkylineProblem

原题传送门1.题目描述2.Solution11、思路分析观察发现,关键点的横坐标总是落在建筑的左右边缘上。这样可以只考虑每一座建筑的边缘作为横坐标,其对应的纵坐标为“包含该横坐标”

原题传送门


1. 题目描述


2. Solution 1

1、思路分析

观察发现,关键点的横坐标总是落在建筑的左右边缘上。这样可以只考虑每一座建筑的边缘作为横坐标,其对应的纵坐标为“包含该横坐标”的所有建筑的最大高度。

观察示例一可以发现,当关键点为某建筑的右边缘时,该建筑的高度对关键点的纵坐标是没有贡献的。如,图中横坐标为7的关键点,虽然它落在红色建筑的右边缘,但红色建筑对其并纵坐标并没有贡献。因此给出“包含该横坐标”的定义: 建筑的左边缘小于等于该横坐标,右边缘大于该横坐标(也就是不考虑建筑的右边缘)。即对于包含横坐标的建筑,有。(The basic idea of this solutions is to find the critical points that change the max height among the buildings on the left)

特别地,在部分情况下,“包含该横坐标”的建筑并不存在。如当图只有一座建筑时,该建筑的左右边缘均对应一个关键点,当横坐标为其右边缘时,这唯一的建筑对其纵坐标没有贡献。因此该横坐标对应的纵坐标的大小为0。

由上面的分析,可以得到一个暴力算法:O(n)地枚举建筑的每一个边缘作为关键点的横坐标,过程中O(n)地检查每一座建筑是否“包含该横坐标”,找到最大高度,即为该关键点的纵坐标。该算法的时间复杂度是O(n^2),需要进行优化。

可以用优先队列来优化寻找最大高度的时间,在从左到右枚举横坐标的过程中,实时地更新该优先队列即可。这样无论何时,优先队列的队首元素即为最大高度。为了维护优先队列,需要使用“延迟删除”的技巧,即无需每次横坐标改变就立刻将优先队列中所有不符合条件的元素都删除,而只需要保证优先队列的队首元素“包含该横坐标”即可。

2、代码实现

package Q0299.Q0218TheSkylineProblem;
import java.util.*;
// The basic idea of this solutions is to find the critical points that change the max height among the buildings on
// the left
public class Solution {
public List> getSkyline(int[][] buildings) {
List> res = new ArrayList<>();
List height = new ArrayList<>(); // height list to store all buildings' heights
for (int[] b : buildings) {
height.add(new int[]{b[0], -b[2]}); // start of a building, height stored as negtive
height.add(new int[]{b[1], b[2]}); // end of a building, height stored as positive
}
Collections.sort(height, (a, b) -> (a[0] == b[0] ? a[1] - b[1] : a[0] - b[0])); // sort the height list
// a pq that stores all the encountered buildings' heights in descending order
PriorityQueue pq = new PriorityQueue<>((a, b) -> (b - a));
pq.offer(0);
int preMax = 0;
for (int[] h : height) {
if (h[1] <0) { // h[1] <0, that means it meets a new building, so add it to pq
pq.offer(-h[1]);
} else { // h[1] >=0, that means it has reached the end of the building, so remove it from pq
pq.remove(h[1]);
}
// the current max height in all encountered buildings
int curMax = pq.peek();
// if the max height is different from the previous one, that means a critical point is met, add to result list
if (curMax != preMax) {
res.add(Arrays.asList(h[0], curMax));
preMax = curMax;
}
}
return res;
}
}

3、复杂度分析

时间复杂度: O(n log n)

空间复杂度: O(n)



推荐阅读
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 2018年人工智能大数据的爆发,学Java还是Python?
    本文介绍了2018年人工智能大数据的爆发以及学习Java和Python的相关知识。在人工智能和大数据时代,Java和Python这两门编程语言都很优秀且火爆。选择学习哪门语言要根据个人兴趣爱好来决定。Python是一门拥有简洁语法的高级编程语言,容易上手。其特色之一是强制使用空白符作为语句缩进,使得新手可以快速上手。目前,Python在人工智能领域有着广泛的应用。如果对Java、Python或大数据感兴趣,欢迎加入qq群458345782。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 栈和队列的共同处和不同处
    本文主要介绍了栈和队列的共同处和不同处。栈和队列都是由几个数据特性相同的元素组成的有限序列,也就是线性表。队列是限定仅在表的一端插入元素、在另一端删除元素的线性表,遵循先进先出的原则。栈是限定仅在表尾进行插入或删除操作的线性表,遵循后进先出的原则。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 数组的排序:数组本身有Arrays类中的sort()方法,这里写几种常见的排序方法。(1)冒泡排序法publicstaticvoidmain(String[]args ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
author-avatar
Anruoxia52
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有