11. 盛最多水的容器

给你 n 个非负整数 a1,a2,...,an每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai)(i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1:
notion imagenotion image
输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1] 输出:1
示例 3:
输入:height = [4,3,2,1,4] 输出:16
示例 4:
输入:height = [1,2,1] 输出:2
提示:
  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104
通过次数613,461提交次数988,196

法 1 双指针(相向指针)

思路
一左一右指针,每次动高度较小的指针,因为移动高度较小的指针后,宽度变小了,但储水高度可能变大,结果还是有可能边大的。而如果动高度较大的,那么宽度变小了,而储水高度不会变高,结果只会变小。
注:储水高度是指左右两边高度值的较小值,参考木桶短板效应!
那如果两个高度相同的话,移动任意一个都可以,因为不存在只有某一条边最为最终答案的情况,要么此时的两条边就是最终答案,要么此时两条边都不是。因为不管往那边走,下一步的储水高度都不会变大,但是此时宽度小了,所以下一步的结果肯定只会变小。
或者这么理解:当两条边相同的话,同时移动两条边。
题解
class Solution: def maxArea(self, height: List[int]) -> int: res = 0 left, right = 0, len(height) - 1 while left < right: h = min(height[left], height[right]) w = right - left res = max(res, h * w) if height[left] < height[right]: left += 1 elif height[left] > height[right]: right -= 1 # 同时移动两条边 else: left += 1 right -= 1 return res ####### class Solution: def maxArea(self, height: List[int]) -> int: res = 0 left, right = 0, len(height) - 1 while left < right: h = min(height[left], height[right]) w = right - left res = max(res, h * w) if height[left] < height[right]: left += 1 # 相同的话,任意移动一条边 else: right -= 1 return res

法 2 暴力法(同向指针)

思路
也是双指针,遍历所有的情况。
题解
class Solution: def maxArea(self, height: List[int]) -> int: res = 0 for i in range(0, len(height)): for j in range(i+1, len(height)): h = min(height[i], height[j]) w = j - i res = max(res, h * w) return res