如何优化解决方案以获得线性性能以找到直方图的孔总面积?

时间:2015-12-04 12:05:05

标签: algorithm performance optimization

所以问题是,给定直方图找到直方图可以容纳的水的总面积,使得如果直方图分别是三个尺寸为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),对于每个单独的条,你在那个条的右侧和左侧找到最大值的最小值,并得到它之间的差异最小 - 最大杆和当前杆以获得将在该杆上保持的水量。等等,直到你通过所有的酒吧。

您如何优化此功能以获得线性性能?

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