题目:给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
分析:maxs = max( min( h(i), h(j) ) * (j - i) ) ,最直接的思路是依次遍历每条边,然后求与其后面的每条边组成的容器的最大面积。求解复杂度O(n^2).
有没有优化的可能?
要想优化,就要找出那些重复或不必要的操作,比如容器一条边为最左侧边时,如果它再小于最右侧边,此时绝无必要再挨个尝试其他边了。同理,如果容器一条边为最右侧时,如果它再小于最左侧边,也没必要遍历其他边。同时保证也能遍历到所有的组合。嗯,该怎么做呢?
最大面积无非就是长乘以高,如果长和高都是最大值,那么乘积当然是最大值,当然还有很多情况不是这样,不过,自然地,可以这么尝试,首先保证x轴方向的最大值,要想做到这个,并不难,我们可以用两个指针分别指向最左(用i表示)或最右(用j表示),这样它们的差值就是长度的最大值,那么此时的高度就是 min(h(i),h(j)), 我们当然希望min(h(i),h(j))这个值尽可能地大,也就是 max( min(h(i),h(j) ) ),
那么如何操作,才能找到这个因子的尽可能大的最大值呢?
如果h(i)更小,既然它更小,要想取得再大的值,可以允许 i自增1,也就是判断 h(i++)的大小,重新获得一种更可能高的可能。同理,如果h(j)更小,j自减1,判断 h(j--),求其与 h(i) 的较小值,分析到这里,已经走了一大步,不过我们担心的是陷入局部最优解,
这种方式要想保证全局最优,如何做到?
设定变量 res 表示当前的全局最优解,如果下一步求出的解,也就是 (j-i) * min(h(i),h(j)),与 res 比较,选取两者较大值,并重新赋值给 res,这样始终保证 res 为全局最优解。
class Solution:
def maxArea(self, height: List[int]) -> int:
i, j, res = 0, len(height) - 1, 0
while i < j:
if height[i] < height[j]:
res = max(res, height[i] * (j - i))
i += 1
else:
res = max(res, height[j] * (j - i))
j -= 1
return res
推荐阅读