重叠图像的最优算法

时间:2015-01-30 16:42:28

标签: algorithm

对于以下问题,我想要一个复杂度小于O(n ^ 2)的算法。

有N个相同高度但宽度不同的图片相互重叠。将为所有图片提供沿x轴的起点和终点坐标。你必须告诉我,从顶部可以看到多少张照片。因为,高度相同,你不必考虑有关高度或任何沿y轴的任何事情。

我使用的算法几乎是强制性的,并且导致了O(n ^ 2)复杂度。我需要一些更好的方法。

给予输入的顺序将代表z顺序。第一张图片将位于最下方位置,第二张图片将位于第一张图片上方,第三张图片将位于第二张图片上,依此类推..(您可以考虑逐张推送图片的垂直堆栈)

1 个答案:

答案 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)始终返回任何非背景图片的值。)然后,依次为每张图片添加:

  1. 查找prec(L(i))。让这个转变为t =(j,y)。 (prec(L(i))必须返回一个值,因为背景图片在-inf处有一个开始转换。)
  2. 设置v = t。
  3. 如果pos(y)< L(i)然后设置t = succ(t)。
  4. 而pos(t)< = R(i):
    • 设置u = succ(t)。
    • 如果pos(t)<然后R(i)设定v = t。
    • 从活动转换列表中删除t(O(log n)时间)。
    • 设置t = u。 (你只是一个临时变量来保存t的下一个值。)
  5. 将(i,L(i))插入到活动转换列表中,以表示图片i的可见范围的开始。
  6. 前一个内循环在最后(最右边)有效转换时离开v,其中x co-ord< R(i)中。此过渡指示将在pos(v)处可见的图片是当图片i的跨度在R(i)处结束时将恢复可见的图片,因此插入(pic(v),R(i))进入活跃的转换列表以反映这一点。
  7. 步骤3和4删除任何被覆盖的过渡。虽然看起来这个内部循环可能会导致二次时间,但它不会,因为任何插入的转换将被整个算法中的这个内部循环最多删除。只插入2n个转换,因此在所有外循环迭代中,此内部循环最多可以移除2n个转换。

    到目前为止,我们将拥有一个活动的转换列表,其中包含最多2n个转换,用于描述所有图片的可见性。在此列表上从左到右进行线性时间传递,为其包含的每个过渡(i,x)设置标记[i]。最后,计算设置了可见标志的图片数量:这就是答案。 (我们需要单独的步骤,因为如果图片上面有许多较窄的图片,图片可能会多次出现。)