这是在高盛采访中问我的。
我们有一个数组,其中i th 元素表示保持在i 位置的块(具有固定的高度和宽度)的数量,就像集水问题一样。我们必须从顶部移走最少的积木,以确保下雨时不会积水。
我想出的解决方案是,我们必须确保最终的结构使得某些x th 是峰值,并且在达到极限之前,左侧和右侧的元素都不会增加。我们可以对每个元素进行处理,并找到所有结果中的最小值。 我所做的一个轻微优化是,我可以检查第i个 th 位置是否可以达到峰值。如果第i个元素的左侧和右侧至少有一个元素的高度低于当前位置,则第i个元素都可以是峰值。
面试官让我以某种方式使用无法解决的集水问题(参考:https://www.geeksforgeeks.org/trapping-rain-water/)。
我想知道是否有更好的解决方案来解决上述问题。
答案 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)