More than code

More Than Code
The efficiency of your iteration of reading, practicing and thinking decides your understanding of the world.
  1. 首页
  2. daily
  3. 正文

Daily C/C++ skyline problem

2021年7月13日 564点热度 0人点赞 0条评论

skyline problem

今天leetcode的每日一题,感觉是一道很不错的题,所以拿出来分享一下

题目链接

还有一篇讲的不错的文章 链接

这种问题的解法总是一步一步迭代出来的,这里我打算讲一种思路,三个实现方法

首先我们可以考虑一种很暴力的解法,就是从左到右枚举每一个横坐标(注意是离散化后的),然后枚举每一个矩形,判断能够包含这个横坐标的最大的矩形高度是多少,这样我们就可以确定这个关键点的纵坐标了

可以想到,我们枚举横坐标是一个必须的过程,因为我们最终要求出所有的关键点。但是我们不必每次都枚举所有的矩形,只要枚举和我当前横坐标有关的矩形就可以

虽然这样的做法复杂度还是n方的,但是这可以启发我们,不一定要在每一个横坐标上枚举矩形,而是利用矩形帮我们更新横坐标

想象现在有一条从左到右的扫描线,他会扫描每一个矩形的边缘。对于每一个边缘来说,我们要么是在集合中添加一个高度,要么是在集合中删除一个高度,即对应了矩形左右边缘。

那么我们对于每一个横坐标,只要找当前集合中的最大值即可

for edge in edges:
    if edge is left_edge:
        set.insert(edge)
    else
        set.erase(edge)
    height[edge] = set.max_element

根据这个伪代码,我们可以利用c++的multiset来实现这个算法

毕竟multiset底层是平衡树,功能还是比较强大的,并且处理这个问题是十分合适的,所以代码会显得比较简单

那么如果不用平衡树呢,我们就可以用线段树

对于线段树来说,做这道题的思路就更为暴力了一些。我们只需要在离散化后的坐标系中画出这些矩形即可

对于一个矩形,我们在其对应的区间上进行区间赋值,然后对于每一个横坐标来说,我们单点查询这个横坐标的高度即可

注意对于区间赋值的情况,我们希望高的矩形覆盖矮的矩形,所以我们可以用高度较小的矩形开始枚举。这样就不需要在赋值的时候考虑最值的问题了。

那么如果我们不用线段树呢?就需要我们回到扫描线的思路中,维护最值的还有一个很好用的数据结构就是堆,或者叫优先队列

但是优先队列无法满足可以直接删除某一个元素的操作,这样我们可以在插入矩形高度的同时,插入对应矩形的右边缘,用来记录该高度何时失效。

在枚举到某一个横坐标的时候,我们可以查看优先队列中的队首元素,如果该元素的横坐标小于我们当前的坐标,表示该高度已经失效,我们就将其pop出来

所以根本思路实际上是利用横坐标来进行了一个延迟删除。这样保证了维护高度的正确性,算法正确性也就得到了保证

标签: c++ daily
最后更新:2021年7月13日

sheep

think again

点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2021 heavensheep.xyz. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS