11.盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
直接两趟for循环暴力求解的话会超出时间限制,不可取
代码如下:
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
res = 0
for i in range(len(height) - 1):
for j in range(len(height)):
area = (j - i) * min(height[i],height[j])
res = max(res,area)
return res
本题较优的解法是使用双指针
分析:
双指针简单来说就是,指针每一次移动,都意味着排除掉一个柱子。
本题的核心就是这个面积是由较短的柱子来决定的,这个影响到了每次指针的移动方向
容纳水量是由两个指向的数字中较小值 * 指针之间的距离所决定
双指针代表了什么?
双指针代表的是可以作为容器边界的所有位置的范围。在一开始,双指针指向数组的左右边界,表示数组中所有的位置都可以作为容器的边界,因为我们还没有进行任何尝试。在这之后,我们每次将对应的数字较小的那个指针往另一个指针的方向移动一个位置,就表示我们认为这个指针不可能作为容器的边界了。
解法一:
class Solution:
def maxArea(self, height: List[int]) -> int:
l, r = 0, len(height) - 1
res = 0
while l < r:
s = min(height[l], height[r]) * (r-l)
res = max(res,s)
if height[l] < height[r]: # 对左右边界进行判断,始终是移动较小的那个指针
l += 1
else:
r -= 1
return res
解法二(for循环):
class Solution:
def maxArea(self, height: List[int]) -> int:
l, r, width, res = 0, len(height) - 1, len(height) - 1, 0
for i in range(width,0 , -1): # 倒序遍历,width就是宽度
if height[l] < height[r]:
res, l = max(res, height[l]*i), l+1
else:
res, r = max(res,height[r]*i), r-1
return res
解法三(优雅,五行解决):
class Solution:
def maxArea(self, height: List[int]) -> int:
res, l, r = 0, 0, len(height) - 1
while l < r:
h = min(height[l],height[r])
res, l, r = max(res, h * (r - l)), l + (height[l] == h), r - (height[r] == h)
return res
这里巧妙的使用了这个height[l] == h