对于以下问题,我想要一个复杂度小于O(n ^ 2)的算法。
有N个相同高度但宽度不同的图片相互重叠。将为所有图片提供沿x轴的起点和终点坐标。你必须告诉我,从顶部可以看到多少张照片。因为,高度相同,你不必考虑有关高度或任何沿y轴的任何事情。
我使用的算法几乎是强制性的,并且导致了O(n ^ 2)复杂度。我需要一些更好的方法。
给予输入的顺序将代表z顺序。第一张图片将位于最下方位置,第二张图片将位于第一张图片上方,第三张图片将位于第二张图片上,依此类推..(您可以考虑逐张推送图片的垂直堆栈)
答案 0 :(得分:0)
这是 O(n log n)算法。我们的想法是,我们将每个图片表示为一对过渡,一个在其左边缘,一个在其右边缘,每个过渡由一对(i,x)组成,被解释为"当从从左到右,图片i在x"处变得可见。我们以从下到上的Z顺序一次添加一个图片,建立一个描述当前状态的转换列表。此列表仅存储"活动"转换 - 即不被某些更高画面遮挡的转换。这意味着除了为我们当前添加的图片添加两个新过渡之外,我们还需要删除它所涵盖的任何过渡。我们将活动转换列表存储在自平衡二进制树中,使其按x co-ord排序,并允许在O(log n)时间内插入和删除。
让我们分别调用图片i左边和右边L(i)和R(i)的x个co-ords。对于转换t =(i,x),我们将写入pic(t)以提取图片索引i和pos(t)以提取x co-ord x。我们还希望能够在列表中(概念上它是一个列表,尽管它被存储为有效查找的二叉树),但是在活动转换中发现最右边的活动转换。一些给定的co-ord x的左边:称为prec(x)。这可以在O(log n)时间内找到。最后,给定转换t,我们希望能够找到其右边的下一个转换:调用此succ(t)。这也可以在O(log n)时间内提取(实际上在摊销的O(1)时间内)。
为避免角落情况,我们首先想象有一些"背景"底部的图像,其左右坐标分别为负和正无穷大。我们将此图片索引指定为-1。所有其他图片都按其在Z顺序中的位置(即按输入顺序)索引。
最初,活动过渡树将仅包含背景图片,我们可以使用过渡(-1,-inf)和(-1,inf)来表示。 (" end"转换是"回到自身",-1并不重要 - 我们关心的是确保succ(t)始终返回任何非背景图片的值。)然后,依次为每张图片添加:
步骤3和4删除任何被覆盖的过渡。虽然看起来这个内部循环可能会导致二次时间,但它不会,因为任何插入的转换将被整个算法中的这个内部循环最多删除。只插入2n个转换,因此在所有外循环迭代中,此内部循环最多可以移除2n个转换。
到目前为止,我们将拥有一个活动的转换列表,其中包含最多2n个转换,用于描述所有图片的可见性。在此列表上从左到右进行线性时间传递,为其包含的每个过渡(i,x)设置标记[i]。最后,计算设置了可见标志的图片数量:这就是答案。 (我们需要单独的步骤,因为如果图片上面有许多较窄的图片,图片可能会多次出现。)