用于切片堆积箱的线性时间算法

时间:2013-12-18 15:40:27

标签: algorithm

我遇到一个时间限制相当有限的问题,并希望看看我是否可以在正确的方向上轻推。

问题在于:

  

你会看到一面墙上有不同高度的柱子。每列高度表示为非零整数。

     

使用长度为 H 的数组 N 定义输入状态,其中包含每个高度   屏幕上的 N 列,例如:

     

Tetris snapshot defined using the <code>H</code> array

     

在给定高度切片快照会留下许多实心碎片   高于那个高度。例如。在2级切片会削减3个实体:

     

Slicing at level 2

     

在第1级切片也会削减3个实体:

     

Slicing at level 1

     

同样,在0级切片会返回单个(一个)实体块,而在3级切片则不会切割任何碎片。

     

要求:给定长度 S 的切片高度 M 数组,包含所有切片高度   应执行“切片”的级别,返回长度 M 的数组,其中包含每个切割的切割件数。

     

例如,根据输入H = {2, 1, 3, 2, 3, 1, 1, 2}S = { 0, 1, 2, 3 },根据上面的示例,程序应返回数量{1, 3, 3, 0}

     

N M 都在20,000左右,但每个数组的高度最高可达到1,000,000

     

解决方案的时间和空间最坏情况复杂性都不能超过   O(N + M + max(M) + max(N))

最后一个约束让我感到困惑:它基本上意味着我不能拥有任何嵌套的for - 循环,而我似乎无法摆脱这种情况。

显然,有一些聪明的预处理需要在每片O(1)中产生最终结果,但我无法想出它。

我继续为每个切片级别创建一个切割数字数组,然后在迭代H时更新所有切割数字,但事实证明这是O(N*M),因为我需要更新所有较低的高度。

是否有适合此任务的数据结构?

2 个答案:

答案 0 :(得分:5)

对于高度上的每个部件,必须有两个与该高度相交的边缘,并且通过“部件”的定义,这组边缘的成员必须全部是不同的。因此,件数是集合中边数的一半。

此外,与特定高度相交的边数是在下方或该高度处开始的边数,减去在其下方或下方完成的边数。

因此,我们可以通过这种方式计算出件数:

  • 创建一个大小为Accumulator的数组max(S),其中填充了零。
  • H进行迭代,对于您遇到的每个垂直边缘,在+1的索引i处添加Accumulator,对应于边缘下端的高度,并且在索引-1处添加j,对应于边缘的上端。我们将“地面”计为零。确保包括前缘和后缘!
  • 迭代Accumulator并在每个单元格中插入所有单元格的总和(包括它)O(max(S))时间(如果保持运行总和)
  • Accumulator中的每个值除以2,得到每个高度的碎片数。
  • 读出与S中的高度相对应的件数。

示例:

边缘的端点,从左到右,是

0,2
1,2
1,3
2,3
2,3
1,3
1,3
0,3

所以我们的Accumulator数组看起来像这样:

{2, 4, 0, -6}

在积累步骤之后,看起来像这样:

{2, 6, 6, 0}

这意味着零件数量

{1, 3, 3, 0} 

作为警告,我刚刚在现场提出这个问题,所以虽然感觉正确,但我没有证据确实是这样。令人鼓舞的是,它也尝试了我尝试过的其他几个例子。

答案 1 :(得分:1)

Step 1: Maintain 3 column list (height, index_start, index_end)
Step 2: Sort the list according to height as primary key (decreasing), index_start as secondary key
Step 3: Let h be the highest height
Step 4: Merge all columns at height at least h and contiguous block
Step 5: Resulting number of blocks is blocks at height h
Step 6: h=h-1
Step 7: Go to step 4

这是粗略的算法。有效的复杂性是O(nlogn)