给定一组矩形,是否有任何重叠?

时间:2015-05-18 15:26:49

标签: algorithm

给定一组矩形表示为元组(xmin, xmax, ymin, ymax),其中xminxmax是左右边缘,yminymax是底部和顶边分别 - 在集合中是否有任何一对重叠的矩形?

一种简单的方法是比较每对矩形的重叠,但这是O(n^2) - 应该可以做得更好。

更新:xminxmaxyminymax整数。因此矩形1和矩形2重叠的条件是xmin_2 <= xmax_1 AND xmax_2 >= xmin_1;类似的Y坐标。

如果一个矩形包含另一个矩形,则该对被认为是重叠的。

3 个答案:

答案 0 :(得分:11)

您可以通过以下方式在O(N log N)方法中进行此操作。

首先,“挤压”你的y坐标。也就是说,在一个数组中将所有y坐标(顶部和底部)排序在一起,然后用排序数组中的索引替换矩形描述中的坐标。现在你所有的y都是从0到2n-1的整数,你的问题的答案没有改变(如果你有相同的y,见下文)。

现在你可以将平面分成2n-1个条纹,每个单位高度,每个矩形完全跨越几个。为这些条纹准备分段树。 (有关分段树概述,请参阅this link。)

然后,对相同数组中的所有x坐标(左右边界)进行排序,为每个坐标保留来自哪个矩形的信息以及这是左边界还是右边界。

然后浏览此列表,当你去的时候,保持当前“活动”的所有矩形的列表,也就是说,你已经看到了左边界而不是右边界。

更准确地说,在您的细分树中,您需要为每个条纹保留多少个活动矩形覆盖它。当遇到左边界时,需要为相应矩形的底部和顶部之间的所有条纹添加1。遇到右边界时,需要减去一个边界。加法和减法都可以使用段树的质量更新(延迟传播)在O(log N)中完成。

要实际检查所需内容,当您遇到左边界时,在添加1之前,检查底部和顶部之间是否至少有一条条纹具有非零覆盖范围。这可以通过在段树中执行区间查询的和来在O(log N)中完成。如果此间隔的总和大于0,则表示您有一个交点。

 squeeze y's
 sort all x's
 t = segment tree on 2n-1 cells
 for all x's
     r = rectangle for which this x is
     if this is left boundary
         if t.sum(r.bottom, r.top-1)>0   // O(log N) request
              you have occurence
         t.add(r.bottom, r.top-1, 1)  // O(log N) request
     else
         t.subtract(r.bottom, r.top-1)  // O(log N) request

你应该仔细考虑是否考虑到触摸是否是一个交叉点,这将影响你对同等数字的处理。如果你考虑触摸一个交叉点,那么你需要做的就是,在排序y时,确保所有具有相同坐标的点的所有顶部都在所有底部之后,并且类似于排序x时,确保所有相等的x都是左派在所有权利之前。

答案 1 :(得分:6)

为什么不尝试平面扫描算法?平面扫描是一种广泛用于计算几何的设计范例,因此它具有经过充分研究并且可在线获得大量文档的优点。看看this。线段交叉问题应该给你一些想法,也就是矩形联合的区域。

阅读关于线段交叉的Bentley-Ottman算法,问题与你的非常相似,它有O((n + k)logn),其中k是交叉点的数量,不过,因为你的矩形边是与x和y轴平行,它更简单,因此您可以修改Bentley-Ottman以在O(nlogn + k)中运行,因为您不需要更新事件堆,因为所有交叉点都可以检测到一次访问矩形并且不会修改扫描线顺序,因此无需保留事件。要使用新矩形检索所有相交的矩形,我建议在每个矩形的ymin和ymax上使用range tree,它将为您提供位于由新矩形的ymin和ymax定义的区间中的所有点,从而矩形与它相交。

如果你需要更多细节,你应该看看M. de Berg等的第二章。 al Computational Geometry book。另外看一下this paper,它们展示了如何在O(nlogn + k)中找到凸多边形之间的所有交点,它可能比我的上述建议更简单,因为所有的数据条纹都在那里解释,你的矩形是凸的,在这种情况下非常好。

答案 2 :(得分:-1)

您可以通过构建不重叠的新矩形列表来做得更好。从矩形集中,取第一个矩形并将其添加到列表中。它显然不与任何其他重叠,因为它是列表中唯一的一个。从集合中取出下一个,看它是否与列表中的第一个重叠。如果是,返回true;否则,将其添加到列表中。对集合中的所有矩形重复。

每次,您都要将矩形r与列表中的r-1矩形进行比较。这可以在O(n*(n-1)/2)O((n^2-n)/2)中完成。您甚至可以将此算法应用于原始集,而无需创建新列表。