LeetCode题练习与总结:天际线问题--218

news2024/9/25 17:16:28

一、题目描述

城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。

每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [lefti, righti, heighti] 表示:

  • lefti 是第 i 座建筑物左边缘的 x 坐标。
  • righti 是第 i 座建筑物右边缘的 x 坐标。
  • heighti 是第 i 座建筑物的高度。

你可以假设所有的建筑都是完美的长方形,在高度为 0 的绝对平坦的表面上。

天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...] ,并按 x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y 坐标始终为 0 ,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。

注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]

示例 1:

输入:buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
输出:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
解释:
图 A 显示输入的所有建筑物的位置和高度,
图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。

示例 2:

输入:buildings = [[0,2,3],[2,5,3]]
输出:[[0,3],[5,0]]

提示:

  • 1 <= buildings.length <= 10^4
  • 0 <= lefti < righti <= 2^31 - 1
  • 1 <= heighti <= 2^31 - 1
  • buildings 按 lefti 非递减排序

二、解题思路

  1. 首先,我们需要将所有建筑物的左边缘和右边缘加入到一个列表中,并按照x坐标进行排序。同时,左边缘的高度为负数,右边缘的高度为正数,这样可以在排序后区分左右边缘。

  2. 然后,我们需要使用一个优先队列(最大堆)来维护当前所有建筑物的高度。优先队列中存储的是负数的高度,这样我们可以确保队列的队首始终是当前最高的建筑物。

  3. 遍历排序后的边缘列表,每次遇到左边缘时,将对应的高度加入优先队列;遇到右边缘时,从优先队列中移除对应的高度。

  4. 在处理每个边缘时,如果当前边缘的x坐标与前一个关键点的x坐标不同,则比较当前优先队列的队首元素(即当前最高建筑物的高度)与上一个关键点的高度。如果不同,则将当前边缘的x坐标和高度(取绝对值)作为一个新的关键点加入结果列表。

  5. 最后,返回结果列表。

三、具体代码

import java.util.*;

class Solution {
    public List<List<Integer>> getSkyline(int[][] buildings) {
        // 存储所有边缘的列表
        List<int[]> edges = new ArrayList<>();
        
        // 将所有建筑物的左边缘和右边缘加入列表
        for (int[] building : buildings) {
            edges.add(new int[]{building[0], -building[2]});
            edges.add(new int[]{building[1], building[2]});
        }
        
        // 按照x坐标进行排序,如果x坐标相同,则按照高度进行排序
        Collections.sort(edges, (a, b) -> {
            if (a[0] != b[0]) {
                return a[0] - b[0];
            } else {
                return a[1] - b[1];
            }
        });
        
        // 优先队列,存储当前所有建筑物的高度(存储负数,以实现最大堆的效果)
        PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);
        pq.offer(0); // 初始化优先队列,加入地面高度
        
        // 结果列表
        List<List<Integer>> res = new ArrayList<>();
        
        // 上一个关键点的高度
        int prevHeight = 0;
        
        // 遍历所有边缘
        for (int[] edge : edges) {
            int x = edge[0];
            int height = edge[1];
            
            // 如果是左边缘,加入优先队列
            if (height < 0) {
                pq.offer(-height);
            } else { // 如果是右边缘,从优先队列中移除
                pq.remove(height);
            }
            
            // 获取当前最高建筑物的高度
            int curHeight = pq.peek();
            
            // 如果当前边缘的x坐标与前一个关键点的x坐标不同,或者高度发生变化
            if (prevHeight != curHeight) {
                res.add(Arrays.asList(x, curHeight));
                prevHeight = curHeight;
            }
        }
        
        return res;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 首先,我们将所有建筑物的左边缘和右边缘加入到一个列表中。这个步骤需要遍历所有建筑物,每个建筑物需要常数时间操作,所以这一步的时间复杂度是 O(n),其中 n 是建筑物的数量。

  • 然后,我们对这个列表进行排序。排序操作的时间复杂度是 O(m log m),其中 m 是列表中元素的数量。由于每个建筑物有左右两个边缘,所以 m = 2n,因此这一步的时间复杂度是 O(2n log (2n)) = O(n log n)。

  • 接下来,我们遍历排序后的边缘列表,并对优先队列进行操作。优先队列的操作(添加和删除)的时间复杂度是 O(log k),其中 k 是优先队列中元素的数量。在最坏的情况下,优先队列可能包含所有建筑物的高度,所以 k ≤ n。因此,遍历边缘列表并操作优先队列的时间复杂度是 O(2n log n) = O(n log n)。

综合以上步骤,代码的总时间复杂度是 O(n log n)。

2. 空间复杂度
  • 我们使用了一个列表 edges 来存储所有建筑物的左边缘和右边缘,这个列表的大小是 2n,所以空间复杂度是 O(n)。

  • 我们使用了一个优先队列 pq 来存储当前所有建筑物的高度。在最坏的情况下,优先队列可能包含所有建筑物的高度,所以空间复杂度是 O(n)。

  • 我们使用了一个列表 res 来存储结果,这个列表的大小最多也是 2n,所以空间复杂度是 O(n)。

综合以上步骤,代码的总空间复杂度是 O(n)。

五、总结知识点

  • 数据结构

    • ArrayList:用于存储建筑物的边缘列表和最终的结果列表。
    • PriorityQueue:实现优先队列,用于维护当前所有建筑物的高度,以确定当前的最高点。
  • 排序

    • Collections.sort():对边缘列表进行排序,使用了自定义的比较器(Comparator)来按照x坐标排序,如果x坐标相同,则按照高度排序。
  • 优先队列

    • PriorityQueue的构造函数中使用了自定义的比较器,以确保队列按高度降序排列(存储负数以实现最大堆效果)。
    • offer()方法:向优先队列中添加元素。
    • peek()方法:获取队列的头部元素,但不移除。
    • remove()方法:从优先队列中移除指定的元素。
  • 算法思想

    • 使用扫描线算法:通过处理每个建筑物的左边缘和右边缘来逐步构建天际线。
    • 使用最大堆(优先队列)来跟踪当前的最高建筑物,以确定天际线上的关键点。
  • 逻辑控制

    • for循环:遍历建筑物的数组以及边缘列表。
    • if语句:判断当前处理的是左边缘还是右边缘,并据此决定是添加还是移除优先队列中的元素。
  • 数学运算

    • 负数的处理:左边缘的高度存储为负数,以便在优先队列中实现最大堆效果。
  • 列表操作

    • Arrays.asList():创建一个包含给定元素的不可变列表。
    • add()方法:向列表中添加元素。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2110110.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Peet‘s Coffee与观测云跨界合作,为伙伴们呈现双重喜悦

随着中秋佳节的临近&#xff0c;国内监控观测行业的领军企业观测云&#xff0c;携手国际知名咖啡品牌 Peets Coffee&#xff0c;共同打造了一款专为中秋佳节定制的特别礼盒&#xff0c;这份礼盒不仅是对传统节日的现代诠释&#xff0c;更是对雅致生活的深情致敬。 Peets Coffe…

【专题】2024年8月医药行业报告合集汇总PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37621 在科技飞速发展的当今时代&#xff0c;医药行业作为关乎人类生命健康的重要领域&#xff0c;正处于前所未有的变革浪潮之中。数智医疗服务的崛起&#xff0c;为医疗模式带来了全新的转变&#xff0c;开启了医疗服务的新时代。…

伴奏提取消除人声如何操作?轻松几步玩转音乐世界

你是否梦想着独自演绎一曲&#xff0c;或是进行个性化的混音创作&#xff0c;却又希望摆脱原唱声音的干扰&#xff1f;那么&#xff0c;学会免费伴奏提取就显得尤为关键。 在这篇文章中&#xff0c;我将为你展示四种简单易学的方法&#xff0c;让你能够轻松地从歌曲中提取出伴…

手机上将mp4转换成amv怎么转?视频转换,3个方法拿捏

在这个社交媒体时代&#xff0c;视频已经成为人们传递信息、表达情感的重要方式之一。然而&#xff0c;不同的设备和平台对视频格式的要求不尽相同&#xff0c;这就需要我们不时地进行视频格式转换&#xff0c;以便在不同的场景中更好地展示和分享我们的作品。 对视频格式转换…

物联网之ESP32控制GPIO输出点亮LED、网页控制LED开关

MENU 前言原理GPIO引脚LED 硬件电路设计软件设计1、点亮一颗LED2、闪烁的LED3、网页控制LED开关 前言 不论学习什么单片机&#xff0c;最简单的外设莫过于IO口的高低电平控制LED&#xff0c;本文介绍如何使用Arduino控制ESP32的GPIO输出。通过本文的学习&#xff0c;掌握一定的…

Qt26代理delegate

代理delegate mainwindowmainwindow.hmainwindow.cpp datedelegatedatedelegate.hdatedelegate.cpp combodelegatecombodelegate.hcombodelegate.cpp spindelegatespindelegate.hspindelegate.cpp main.cpp运行图 mainwindow mainwindow.h #ifndef MAINWINDOW_H #define MAIN…

Java8新特性-Optional的使用

写在前面 最开始学java的时候&#xff0c;总能听到别人说java8的新特性&#xff0c;比如lambda表达式&#xff0c;stream流等等。但是第一次接触Optional是在公司前辈的代码中看到的。最开始我还以为是公司自己的工具类&#xff0c;也没太注意。后来才知道他也是java8最重要的…

西安十大产业园,哪一个将成为你事业的新起点?

每个人在追求事业成功的过程中&#xff0c;都在寻找那个能够助力自己腾飞的平台&#xff0c;而西安的十大产业园无疑提供了丰富多样的选择&#xff1a; 一、西安国际数字影像产业园 1. 园区概况 西安国际数字影像产业园是西安乃至西北地区在数字影像产业领域的重要基地&#…

基于视觉-语言模型的机器人任务规划:ViLaIn框架解析

目录 一、引言二、ViLaln框架介绍总体框架概述对象估计器初始状态估计器目标估计器纠错重提示机制&#xff08;CR&#xff09; 参考文献 一、引言 随着机器人技术的不断发展&#xff0c;如何通过自然语言指令引导机器人执行任务成为了一个重要的研究方向。自然语言作为人与机器…

mysql连接oceanbase数据库集群+租户

mysql集成的有连接oceanbase数据库的方式&#xff0c;所以只需要对参数进行修改即可。 url: jdbc:mysql://[ip地址]:[端口]/[数据库]?useUnicodetrue&characterEncodingUTF-8&serverTimezoneUTC //其他参数根据需求设置username: [用户名][租户名]#[集群名]password: …

【CTF Web】BUUCTF Upload-Labs-Linux Pass-10 Writeup(文件上传+PHP+扩展名双写绕过)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的&#xff0c;专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关&#xff0c;每一关都包含着不同上传方式。 注意 1.每一关没有固定的…

springboot+vue+mybatisjsp广播剧制作订阅系统+PPT+论文+讲解+售后

随着世界经济信息化、全球化的到来和互联网的飞速发展&#xff0c;推动了各行业的改革。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、动态的、交互友好的、高效的广播剧制作订阅系统。当前的信息管理存在工作效…

element-ui打包之后图标不显示,woff、ttf加载404

1、bug 起因 昨天在 vue 项目中编写 element-ui 的树形结构的表格&#xff0c;发现项目中无法生效&#xff0c;定位问题之后发现项目使用的 element-ui 的版本是 2.4.11 。看了官方最新版本是 2.15.14&#xff0c;然后得知 2.4.11 版本是不支持表格树形结构的。于是决定升级 el…

Python 在Excel中应用和取消多种不同类型的数据筛选

目录 安装Python Excel处理库 Python 在 Excel 中应用文本筛选 Python 在 Excel 中应用数字筛选 Python 在 Excel 中应用字体颜色、单元格颜色或图标集筛选 Python 在 Excel 中应用日期筛选 Python 在 Excel 中应用动态日期筛选 Python 在 Excel 中筛选空单元格或非空单…

再做leetcode42hard题接雨水——双指针法

再做leetcode42hard题接雨水——双指针法 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a…

在jenkins中获取git的修改记录的方法

获取 Jenkins API Token&#xff1a; 首先&#xff0c;登录到你的 Jenkins 服务器。 点击右上角的用户名&#xff0c;然后选择“Configure&#xff08;配置&#xff09;”。 在“API Token”部分&#xff0c;生成一个新的 API Token 或使用已有的 Token。 构建 API 请求 URL&a…

k8s上搭建devops环境

一、gitlab 1.安装gitlab # 下载安装包 wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-15.9.1-ce.0.el7.x86_64.rpm # 安装 rpm -i gitlab-ce-15.9.1-ce.0.el7.x86_64.rpm # 编辑 vi /etc/gitlab/gitlab.rb 文件 # 修改 external_url 访问路径 htt…

网络安全工程师培训费用

在当今这个信息化迅猛发展的时代&#xff0c;网络安全已成为各行各业关注的焦点。作为保障网络信息安全的中坚力量&#xff0c;网络安全工程师的需求量逐年攀升。随之而来的是&#xff0c;越来越多的人对网络安全工程师的培训费用充满了好奇。本文将为您详细解析这一问题&#…

内存卡不小心格式化了有办法恢复数据吗?

在数字时代&#xff0c;内存卡作为便携式存储设备&#xff0c;广泛应用于手机、相机等设备中。然而&#xff0c;由于操作不当或设备故障&#xff0c;内存卡有时会被不小心格式化&#xff0c;导致存储在其中的重要数据丢失。 面对这种情况&#xff0c;许多人可能会感到焦虑&…

C语言求100以内的素数

问题&#xff1a;用C语言求出100以内的素数。 分析&#xff1a;素数&#xff0c;即质数&#xff0c;是指只可以被1和本身整除的数。此时可以考虑用循环的方法来用这个数除以所有1001以内的数&#xff0c;若存在余数为0的情况&#xff0c;则说明该数不是素数&#xff1b;此外&am…