【堆 (优先队列) 扫描线】218. 天际线问题

本文涉及知识点

堆 (优先队列) 扫描线

LeetCode218. 天际线问题

城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 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 <= 104
0 <= lefti < righti <= 231 - 1
1 <= heighti <= 231 - 1
buildings 按 lefti 非递减排序

懒删除堆+ 扫描线

通过观察示例,我们可以得出如下结论:
性质一:关键点的横坐标一定是建筑的左右边缘。令建筑的左右边缘的集合是xs。
性质二:xs中除以下元素外,全部是关键点:
∀ \forall x,i ,其中 x ∈ \in xs。 x in $[lefti,righti] x对应的height 小于等于heighti。
性质三:根据性质二,一个x对应多个height,取最大值。xh记录x及对应高度。
性质四:根据性质三,性质二可以简化为 x in $(lefti,righti)
lh 记录左边界及高度。
rh记录有边界及高度。
xh、lh、rh都按x的升序排序。
有序mulset has代替懒删除堆 记录:
lefti < x ,righti > x的高度。 如果高度的最大值小于x对应的高度,则是关键点。

关键点的纵坐标y
{ 0 不存在 l e f t i 小于等于 x , r i g h t i 大于 x 的建筑 这些建筑的最大高度 o t h e r \begin{cases} 0 && 不存在lefti小于等于x,righti大于x的建筑\\ 这些建筑的最大高度 && other \\ \end{cases} {0这些建筑的最大高度不存在lefti小于等于x,righti大于x的建筑other
如果两个相邻的关键点高度相同,删除前面的关键点。

代码

核心代码

  class Solution {public:vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {vector<pair<int, int>> tmp,xh, lh, rh;for (const auto& v : buildings) {lh.emplace_back(make_pair(v[0], v[2]));rh.emplace_back(make_pair(v[1], v[2]));}tmp = lh;tmp.insert(tmp.end(), rh.begin(), rh.end());sort(tmp.begin(), tmp.end());sort(rh.begin(), rh.end());		 for (const auto& [x, h] : tmp) {if (xh.size() && (xh.back().first == x)) {xh.back().second = h;}else {xh.emplace_back(make_pair(x, h));}}multiset<int> has;int il = 0, ir = 0;vector<vector<int>> ret;for (const auto& [x, h] : xh) {			 while ((il < lh.size() )&& (lh[il].first < x)) {has.emplace(lh[il++].second);}while ((ir < rh.size()) && (rh[ir].first <= x)) {has.erase(has.find(rh[ir].second));ir++;}if (has.empty() || (*has.rbegin() < h)) {ret.emplace_back(vector<int>{ x,-1 });}while ((il < lh.size()) && (lh[il].first <= x)) {has.emplace(lh[il++].second);}ret.back()[1] = has.empty()?0: *has.rbegin();	 }		vector < vector<int>> ret2 = { ret[0] };for (int i = 1; i < ret.size(); i++) {if (ret2.back()[1] != ret[i][1]) {ret2.emplace_back(ret[i]);}}return ret2;}};

单元测试

template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{Assert::AreEqual(t1, t2);
}template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{Assert::AreEqual(v1.size(), v2.size());for (int i = 0; i < v1.size(); i++){Assert::AreEqual(v1[i], v2[i]);}
}template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{sort(vv1.begin(), vv1.end());sort(vv2.begin(), vv2.end());Assert::AreEqual(vv1.size(), vv2.size());for (int i = 0; i < vv1.size(); i++){AssertEx(vv1[i], vv2[i]);}
}namespace UnitTest
{	vector<vector<int>> buildings;TEST_CLASS(UnitTest){public:TEST_METHOD(TestMethod00){buildings = { {2,9,10},{3,7,15},{5,12,12},{15,20,10},{19,24,8} };auto res = Solution().getSkyline(buildings);AssertV2(vector<vector<int>>{ {2, 10}, { 3,15 }, { 7,12 }, { 12,0 }, { 15,10 }, { 20,8 }, { 24,0 }}, res);}TEST_METHOD(TestMethod01){buildings = { {0,2,3},{2,5,3} }		;auto res = Solution().getSkyline(buildings);AssertV2(vector<vector<int>>{ {0, 3}, { 5,0 }}, res);}};
}

简化思路

所有x都是关键点,除非y和前一个x相同。
y = max(所有左边界 <= x,右边界大于x的建筑高度),所有没有符合的建筑y为0。

class Solution {
public:vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {vector<pair<int, int>> tmp, xh, lh, rh;for (const auto& v : buildings) {lh.emplace_back(make_pair(v[0], v[2]));rh.emplace_back(make_pair(v[1], v[2]));}tmp = lh;tmp.insert(tmp.end(), rh.begin(), rh.end());sort(tmp.begin(), tmp.end());sort(rh.begin(), rh.end());for (const auto& [x, h] : tmp) {if (xh.size() && (xh.back().first == x)) {xh.back().second = h;}else {xh.emplace_back(make_pair(x, h));}}multiset<int> has;int il = 0, ir = 0;vector<vector<int>> ret;for (const auto& [x, h] : xh) {while ((il < lh.size()) && (lh[il].first <= x)) {has.emplace(lh[il++].second);}while ((ir < rh.size()) && (rh[ir].first <= x)) {has.erase(has.find(rh[ir].second));ir++;}int y = has.empty() ? 0 : *has.rbegin();if (ret.empty() || (ret.back()[1] != y)) {ret.emplace_back(vector<int>{x, y});}}return ret;}
};

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关推荐

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

景芯SoC训练营DFT debug

景芯训练营VIP学员在实践课上遇到个DFT C1 violation&#xff0c;导致check_design_rule无法通过&#xff0c;具体报错如下&#xff1a; 遇到这个问题第一反映一定是确认时钟&#xff0c;于是小编让学员去排查add_clock是否指定了时钟&#xff0c;指定的时钟位置是否正确。 景芯…

C语言文件操作-文件IO(系统调用)

文件IO (系统调用) 文件描述符open函数read函数write函数lseek函数close函数dup函数dup2函数 stat函数getpwuid函数getgrgid函数 实例 目录操作 opendir函数readdir函数rewinddir函数closedir函数实例 文件IO (系统调用) 文件IO就是系统调用&#xff0c;用户空间进入内核空间…

2024年信息系统项目管理师1批次上午客观题参考答案及解析(3)

51、探索各种选项&#xff0c;权衡包括时间与成本、质量与成本、风险与进度、进度与质量等多种因素&#xff0c;在整个过程中&#xff0c;舍弃无效或次优的替代方案&#xff0c;这种不确定性应对方法是()。 A&#xff0e;集合设计 B&#xff0e;坚韧性 C&#xff0e;多种结果…

离线运行Llama3:本地部署终极指南_liama2 本地部署

4月18日&#xff0c;Meta在官方博客官宣了Llama3&#xff0c;标志着人工智能领域迈向了一个重要的飞跃。经过笔者的个人体验&#xff0c;Llama3 8B效果已经超越GPT-3.5&#xff0c;最为重要的是&#xff0c;Llama3是开源的&#xff0c;我们可以自己部署&#xff01; 本文和大家…

衡量股票价值的尺度

劳伦女士说&#xff0c;“邓普顿猎取便宜股的时候&#xff0c;总是运用证券分析师的‘一百种价值衡量尺度’中的好几种。 原因之一呢&#xff0c;就是因为任何一种衡量方法都是万能的&#xff0c;在不同的时期、不同的市场环境下&#xff0c;总会有它自己的局限性。就像有朋友…

大数据------JavaWeb------FilterListenerAJAXAxiosJSON

Filter Filter简介 定义&#xff1a;Filter表示过滤器&#xff0c;是JavaWeb三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一。 作用&#xff1a;它可把对资源&#xff08;Servlet、JSP、Html&#xff09;的请求拦截下来从而实现一些特殊功能 过滤器一般完成…

【QT中实现摄像头播放、以及视频录制】

学习分享 1、效果图2、camerathread.h3、camerathread.cpp4、mainwindow.h5、mainwindow.cpp6、main.cpp 1、效果图 2、camerathread.h #ifndef CAMERATHREAD_H #define CAMERATHREAD_H#include <QObject> #include <QThread> #include <QDebug> #include &…

SAP顾问的核心竞争力是什么?

最近看到几个业内大佬在讨论这个话题&#xff0c;我也想谈谈我的看法。这位大佬的原话是“SAP顾问的核心技能不是配置软件&#xff0c;而是对财务、供应链、销售等运行流程的理解&#xff0c;解决的是企业流程和数据标准化的问题。” 我先不做评价&#xff0c;我先问几个问题。…

选择排序(C语言版)

选择排序是一种简单直观的排序算法 算法实现 首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起始位置。 再从剩余未排序元素中继续寻找最小&#xff08;大&#xff09;元素&#xff0c;然后放到已排序序列的末尾。 重复第二步&…

【k8s安装redis】k8s安装单机版redis实现高性能高可用

文章目录 简介一.条件及环境说明&#xff1a;二.需求说明&#xff1a;三.实现原理及说明四.详细步骤4.1.创建configmap 配置文件4.2.创建StatefulSet 配置4.3.创建service headless 配置 五.安装说明 简介 本文将根据在k8s环境中搭建【伪】单机模式的redis实例。由于共享存储的…

020-GeoGebra中级篇-几何对象之点与向量

本文概述了在GeoGebra中如何使用笛卡尔或极坐标系输入点和向量。用户可以通过指令栏输入数字和角度&#xff0c;使用工具或指令创建点和向量。在笛卡尔坐标系中&#xff0c;示例如“P(1,0)”&#xff1b;在极坐标系中&#xff0c;示例如“P(1;0)”或“v(5;90)”。文章还介绍了点…

深入理解循环神经网络(RNN)

深入理解循环神经网络&#xff08;RNN&#xff09; 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类专门处理序列数据的神经网络&#xff0c;广泛应用于自然语言处理、时间序列预测、语音识别等领域。本文将详细解释RNN的基本结构、工作原理以及其优…

uniapp本地打包到Android Studio生成APK文件

&#xff08;1&#xff09;安装 Android Studio 软件&#xff1b; 下载地址&#xff1a;官方下载地址&#xff0c;英文环境 安装&#xff1a;如下之外&#xff0c;其他一键 next &#xff08;2&#xff09;配置java环境&#xff1b; 下载&#xff1a;j…

基于SpringBoot构造超简易QQ邮件服务发送 第二版

目录 追加 邮箱附件 添加依赖 编码 测试 第二版的更新点是追加了 邮箱附件功能 ( 后期追加定时任务 ) 基于SpringBoot构造超简易QQ邮件服务发送(分离-图解-新手) 第一版 追加 邮箱附件 添加依赖 <!-- 电子邮件 --><dependency><groupId>org.spri…

Java小白入门到实战应用教程-介绍篇

writer:eleven 介绍 编程语言介绍 编程语言按照抽象层次和硬件交互的方式划分为低级编程语言和高级编程语言。 低级编程语言更接近计算机硬件层面&#xff0c;通常具有执行效率高的特点&#xff0c;但是由于注重计算机底层交互&#xff0c;所以编程难度相对较大。 高级编程…

国内开源RAG知识库ChatWiki MaxKb QAnyThing对比

RAG 知识库 &#xff0c; 是一个比较火的赛道&#xff0c;以下是国内开源的RAG 知识库 ChatWiki 芝麻小客服开源的一个RAG 知识库&#xff0c;核心特点是和人工聊天系统打通&#xff0c;可以作为对外的聊天系统使用。 开源地址 https://github.com/zhimaAi/chatwiki 云端体…

如何评价Flutter?

哈喽&#xff0c;我是老刘 我们团队使用Flutter已经快6年了。 有很多人问过我们对Flutter的评价。 今天在这里回顾一下6年前选择Flutter时的原因&#xff0c;以及Flutter在这几年中的实际表现如何。 选择Flutter时的判断 1、性能 最开始吸引我们的就是其优秀的性能。 特别是…

【vue3|第16期】初探Vue-Router与现代网页路由

日期:2024年7月6日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^ 1.01365 = 37.7834;0.99365 = 0.0255 1.02365 = 1377.4083…

力扣第226题“翻转二叉树”

在本篇文章中&#xff0c;我们将详细解读力扣第226题“翻转二叉树”。通过学习本篇文章&#xff0c;读者将掌握如何使用递归和迭代的方法来翻转二叉树&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理解。 问题描述 力扣第…

深入探索联邦学习框架 Flower

联邦学习框架 本文主要期望介绍一个设计良好的联邦学习框架 Flower&#xff0c;在开始介绍 Flower 框架的细节前&#xff0c;先了解下联邦学习框架的基础知识。 作为一个联邦学习框架&#xff0c;必然会包含对横向联邦学习的支持。横向联邦是指拥有类似数据的多方可以在不泄露…