你得到一个n点,在数组中未分类。您应该找到两个覆盖所有点的矩形,它们不应重叠。矩形的边缘应平行于x或y纵坐标。
该程序应返回所有这些点所覆盖的最小区域。第一个矩形的区域+第二个矩形的区域。
我试图解决这个问题。我按X纵坐标对点进行排序,第一个是第一个矩形的最左边一个。当我们通过积分时,我们找到最高点和最低点。我在想,当两个点之间的差异乘以x时,这意味着第一个点是第一个矩形中最右边的一个,第二个点是第二个矩形中最左边的一个。
它应该在第一个示例中给出点时起作用,但是,如果示例是第二个示例则它不起作用。因为它会返回类似这样的东西,这是错误的:
这应该是正确的:
然后我想要做两次排序,只是,第二次用Y纵坐标做,然后比较两个总面积。当点按x排序并且点按y排序且较小区域是正确答案时的区域。
答案 0 :(得分:2)
两个矩形不能重叠,因此一个必须完全在右边或在另一个上面。你想按x值对点进行排序并找到最大差距的想法是好的,但你应该按照你的建议对两个方向进行分类。那会在你的例子中找到正确的矩形。
然而,最大的差距不一定是理想的分裂点。取决于垂直方向上的边界框的范围,分割可以在其他地方。考虑一个带有四个象限的矩形区域,其中两个对角相对的象限填充有点:
在这里,理想的分裂不是最大的差距。
您可以通过考虑具有相邻x坐标和y坐标的点之间的所有可能分割来找到理想位置。
然后对最小的顶部和底部矩形执行相同的操作。最后两个步骤可以组合在一起,这将为正确矩形的最小边界保存数组。
这应该是O(n·log n)及时:排序是O(n·log n),单个遍是O(n)。对于第一个矩形的运行边界框,你需要O(n)额外的内存。
答案 1 :(得分:1)
第一个观察是矩形的任何边都必须触及其中一个点。没有触及某个点的边缘可能会被拉回,导致面积减少。
给定n个点,因此对于left1,right1,bottom1,top1,left2,right2,bottom2和top2总共有n个选择。这给出了一个简单的O(n ^ 8)算法:尝试所有可能的分配,并记住给出最小总面积(right1 - left1)(top1 - bottom1)+(right2 - left2)(top2 - bottom2)的算法。实际上,你可以跳过任何正确的组合<左或上<底部。这给出了加速,但它不会改变O(n ^ 8)的界限。
另一个观察结果是边缘应该保持在所有点的最小和最大X和Y范围内。找出任何点的最小和最大X和Y值。将这些minX,maxX,minY和maxY称为。至少有一个矩形需要分别在这些级别上有左,右,下和上边缘。
因为必须将minx,maxX,minY和maxY分配给两个矩形中的一个,并且正好有2 ^ 4 = 16种方法,所以您可以尝试四种可能的分配中的每一种,其余的坐标分配为以上。这给出了一个O(n ^ 4)算法:O(n)得到minX,maxX,minY和maxY,然后是O(n ^ 4)来填充minX,maxX的16个赋值中的每一个的四个未赋值变量, minY和maxY到八个边缘坐标。
到目前为止,我们忽略了矩形不重叠的要求。为了适应这种情况,我们必须确保满足以下四个条件中的至少一个:
当且仅当所有这四个条件同时为假时,两个矩形重叠。这允许我们跳过候选解,提供加速但不改变渐近约束O(n ^ 4)。请注意,我们需要特别检查这个条件,否则,最佳解决方案可能会重叠(练习:显示这样的示例)。
让我们试着再多花些时间。假设我们通过上面的条件#1有非重叠的矩形。那么h有n个选择;我们可以尝试这n个选项中的每一个,然后通过找到结果中的点的最小和最大坐标来确定结果选择的区域。通过尝试h的所有n个选择,我们可以确定最佳情况"垂直分裂。我们不需要尝试条件#2,因为唯一的区别在于矩形的排序是任意的。我们还必须尝试使用水平分割的条件#3。这表明O(n ^ 2)算法:
我们能做得更好吗?这是O(n ^ 2)而不是O(n),因为对于h
和w
的每个选择,我们需要找到每个子组的最小和最大坐标。假设通过两个子组进行线性扫描。当水平/垂直扫描时,我们实际上不需要为最小和最大X / Y坐标执行此操作,因为这些将是已知的。我们需要的是解决这个问题的方法:
给定n个点和值h,找到Y坐标不大于h的任何点的最大X坐标。
我上面给出的一个显而易见的解决方案是O(n ^ 2),但你可以通过巧妙的排序应用找到一个O(n log n)解决方案,甚至可以通过更多的O(n)解决方案来找到聪明的方法。我不会尝试这个。
我们的解决方案是O(n ^ 2);理论上最优的解是Omega(n),因为你必须至少看看所有的点。所以我们非常接近,但还有改进的余地。