【C/C++】715. Range 模块(二)

130 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情


题目链接:715. Range 模块

题目大意

题目详细描述以及示例和提示可以点击 题目链接715. Range 模块(一)进行查看,这里只对题目大意进行一个描述。

[1,109][1, 10^9] 中给定区间范围,对给定区间范围做添加、删除和查询操作:

  • 添加操作:将给定区间标记为可跟踪状态,也就是在查询时如果查询的是该区间内的子区间时返回 true
  • 删除操作:将给定区间标记为不可跟踪状态,也就是在查询时如果查询的是该区间内的子区间时返回 false
  • 查询操作:查询给定区间是否都为可跟踪状态,是返回 true,否则返回 false

需要注意给定区间都是 左闭右开区间,包括左区间端点但不包括右区间端点。

解题思路分析

前文 715. Range 模块(一) 对题目进行了初步的解题分析,接下来对解题思路的具体操作进行详细描述

  • 对于添加操作 addRange(left, right) 的左区间节点分为如下几种情况(注意区间节点 prev(iter) 的值一定是小于等于 left 的):

    1. 在集合中存在完全包含 [left, right] 的区间,此时直接返回即可。 715-1.jpg

    2. 与集合中的区间存在交集,此时需要合并为更大的区间,更具体的为先修改当前插入区间的左端点为即将合并的区间左端点,使得区间范围更大。 715-2.jpg

    3. 与集合中的区间无交集,(注意这里是与最后一个小于等于 left 的区间节点,并非一定与后面的区间节点无交集,当前只考虑左区间节点的情况。)无需处理左端点。 715-3.jpg

处理完添加区间的左端点后,处理添加区间的右端点,首先将集合中包含在添加区间内的区间都删除,也就是合并区间,将这些区间与添加区间进行合并。

715-4.jpg

  • 对于添加操作 addRange(left, right) 的右区间端点分为如下几种情况:
    1. 小于集合中已有区间的左端点时,无需合并区间(注意是小于,没有等于) 715-5.jpg

    2. 大于等于集合中已有区间的左端点,且小于等于集合中已有区间的右端点,此时需要与该集合进行合并处理。 715-6.jpg

最后保证集合中所有区间都不会和 [left,right) 有交集即可在集合中插入该区间。

按照同样的思路进行删除操作 removeRange(left, right),对于删除的区间 [left, right],我们只需判集合中的区间是否包含 leftright,判断是否需要将集合中的区间做减集。如:

715-7.jpg

对于删除区间左端点 left 和右端点 right,判断在集合中已有区间上的情况,分为在区间里和在区间外两种情况,但是最后都是需要删除区间内相交的部分,保留不相交的部分:

715-8.jpg

阶段总结

  • 该题的 核心思想 在于查找有序集合中与当前区间的重叠部分,分别对左端点和右端点进行相应处理即可。
  • 需要注意的是在有序集合中二分查找时的技巧,利用 prev(upper_bound(left)) 来寻找最大的一个小于等于 left 的区间节点。
  • 在删除集合中的元素时,需要特别注意迭代器指向问题,因为在删除迭代器指向的元素后,再对迭代器进行相应操作的话就像对空指针进行操作,会出现没有定义的情况。 该节对题目核心的难点进行了详细描述,解决了添加操作 addRange(left, right) 和删除操作 removeRange(left, right),通过添加和删除操作来维护了该有序集合,这样一来查询操作 queryRange(left, right) 就会变得非常方便,仅需在集合中查找判断即可。下一节将对代码实现部分进行详述。

结束语

对于生活而言,热爱无疑是强有力的助推器。它会赋予你能量,促使你不断探寻生命的更多可能性。心有热爱,眼中自有光芒。去找到你所热爱的事,并为之全力以赴,便能活成自己喜欢的样子。