最少要清除的砖块,以免在集水器中积水

时间:2018-08-02 16:23:49

标签: arrays algorithm optimization data-structures

这是在高盛采访中问我的。

我们有一个数组,其中i th 元素表示保持在i 位置的块(具有固定的高度和宽度)的数量,就像集水问题一样。我们必须从顶部移走最少的积木,以确保下雨时不会积水。

我想出的解决方案是,我们必须确保最终的结构使得某些x th 是峰值,并且在达到极限之前,左侧和右侧的元素都不会增加。我们可以对每个元素进行处理,并找到所有结果中的最小值。 我所做的一个轻微优化是,我可以检查第i个 th 位置是否可以达到峰值。如果第i个元素的左侧和右侧至少有一个元素的高度低于当前位置,则第i个元素都可以是峰值。

面试官让我以某种方式使用无法解决的集水问题(参考:https://www.geeksforgeeks.org/trapping-rain-water/)。
我想知道是否有更好的解决方案来解决上述问题。

1 个答案:

答案 0 :(得分:1)

我们需要回答这个问题:

  • 哪一列将达到最佳峰,即我们需要删除最小数量的块以使其向两侧减小(不增大)的峰?

要回答此问题,对于每一列,我们需要回答以下问题:

  • 要使其达到峰值,需要删除多少个块?

我们可以将其分为两个问题:

  • L(i) =需要在左侧删除几块?
  • R(i) =需要在右侧删除多少个块?

L(i)可以如下得出:

  • 如果左列小于或等于,则使一个峰达到的块数将与使该峰成为峰的块数相同。因此:

    if (column i-1 <= column i) L(i) = L(i-1)

  • 如果左列较大,我们需要找到左侧的第一列j,该列小于或等于i。然后要删除的块(向左)以使i达到峰值(L(i))将成为要删除的块以使j达到峰值(L(j))加上要删除的块,以使介于两者之间的所有内容等于i

    如果我们可以循环遍历各列以达到目标,那么这将足够简单,但是要高效地执行此操作则需要更复杂一些。

    请注意,我们只关心小于j first 元素i,这意味着该元素{{ 1}}比我们根本不在意的k大(em)(因为可能返回j(即j的任何东西都将返回) k可以做到这一点,因为k <= i,因此j)。这也意味着我们只需要处理任何给定的列一次,因为如果我们要遍历各列以查找更少的列,那么我们遍历的所有内容都会变得更大,因此与右边的列无关

    这将导致我们以下内容:

    • 保留一堆递增的列。

      技术说明:我们需要将列的索引存储在堆栈中,而不是列的值,因为我们还需要知道列在哪里。在下面的示例中,我仅使用这些值来提高可读性。

    • 使用此堆栈,我们可以通过从堆栈中弹出大于列j <= k的元素并乘以弹出值和列{{1}之间的差和距离,来快速计算给定的j <= i }。

    这里是使它不太抽象的示例。如果我们有:

    L(i)

    要使5达到峰值(i,我们将得到i-也就是说,将5和下一个较小的元素4之间的所有元素都设为5,并将之间的所有元素都等于5。 4,下一个较小的元素2应该等于4。

    要从此处将3变为峰值,我们需要将以上([2,6,4,9,5,3] 0,1,2,3,4,5 i 0,0,2,2,6,12 L(i) stack after 5 = [2,4,5] stack after 3 = [2,3] [2,4,4,5,5,3] to make 5 a peak [2,3,3,3,3,3] to make 3 a peak )添加到要删除的块中,以将所有5变为3(即L(4) = 6),并将4变为3。 (即[2,4,4,5,5,3])。

    例如,如果在此之后获得1,则可以仅使用2和3进行相同的操作(因为我们已经知道使中间所有列等于3的成本)。

    < / li>

6可以与2 columns*(5-3) = 4完全相同,只是方向相反。

最后,我们只需要返回将产生最佳峰的列2 columns*(4-3) = 2

这需要O(n)时间和O(n)空间。

这里有一些Python 3代码可以做到这一点:

R(i)