所以问题是,给定直方图找到直方图可以容纳的水的总面积,使得如果直方图分别是三个尺寸为5,3,5的条,那么它可以容纳的水的总面积是2,因为直方图只能将水保持在第二个杆(3)的顶部,因为它的相邻杆较大,形成一个孔。任何超过2,水将从两侧流出。更多例子:
我:[5 2 3 2 4] O:5
我:[2 5 1 4 7 3 1 5 1] O:(4 + 1)+(2 + 4)= 11 在杆2和杆5之间以及杆5和杆8之间存在孔
我的解决方案是一种蛮力解决方案,需要O(n ^ 2),对于每个单独的条,你在那个条的右侧和左侧找到最大值的最小值,并得到它之间的差异最小 - 最大杆和当前杆以获得将在该杆上保持的水量。等等,直到你通过所有的酒吧。
您如何优化此功能以获得线性性能?
答案 0 :(得分:2)
构建两个数组,其中包含当前一个(包括其自身)左侧和右侧的最大元素。您可以在线性时间内构建每个。 以你的例子:
left: [5 5 5 5 5]
right: [5 4 4 4 4]
现在再次运行原始输入并求和min(left[i], right[i]) - I[i]
。由于现在发现max只是一个查找,整个算法就是O(N)。
你可以证明这是正确的,因为对于一个位置i,如果你可以将水位提高到更高的水平,你需要一个至少在那个水平左右的障碍。由于您已经使用了左边的最大值和右边的最大值,因此没有比你选择的更高的障碍。
答案 1 :(得分:0)
迭代输入数组,将每个元素及其位置添加到堆栈中。但在添加任何元素之前,先移除任何较小的元素,然后计算在k处的z和i处的x之间填充多少水,底部为y处的y。
请注意,即使必须从每个元素的堆栈中删除元素,这仍然是O(n),因为每个元素将进入和退出堆栈一次。
这是一个示例Python代码:
from collections import deque
def solve(A):
answer = 0
Q = deque()
for i, x in enumerate(A):
while len(Q) and Q[-1][1] < x:
j, y = Q.pop()
if len(Q):
k, z = Q[-1]
height = min(x, z) - y
width = (i - k - 1)
answer += height * width
Q.append((i, x))
return answer
print solve([2, 5, 1, 4, 7, 3, 1, 5, 1]) #11
print solve([5, 2, 3, 2, 4]) #5
print solve([5, 3, 5]) #2