1:问题描述
来源:LeetCode
难度:中等
问题详情:
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
**说明:**你不能倾斜容器。
示例1:
输入:[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
2:问题分析
2.1 时间复杂度和空间复杂度
在真正开始介绍各种算法前,先以表格形式展示各自的时间复杂度和空间复杂度,其中 N N N表示列表 h e i g h t height height的长度。
算法 | 时间复杂度 | 空间复杂度 |
---|---|---|
双指针 | O ( N ) O(N) O(N) | O ( 1 ) O(1) O(1) |
2.2 双指针
2.2.1 流程
- 首先初始化一个头指针和尾指针分别指向数组的最左边和最右边,并且赋值最大面积 m a x _ a r e a = 0 max\_area=0 max_area=0
- 计算当前面积,计算面积的公式为:
a r e a = ( t a i l − h e a d ) × m i n ( h e i g h t [ t a i l ] , h e i g h t [ h e a d ] ) area =(tail-head)×min(height[tail],height[head]) area=(tail−head)×min(height[tail],height[head]) - 更新当前的最大面积
m a x _ a r e a = m a x ( m a x _ a r e a , a r e a ) max\_area=max(max\_area,area) max_area=max(max_area,area) - 比较头尾指针指向的数值大小
- 将较小者指针向中间移动
- 重复上述步骤直至头尾指针指向同一位置
- 输出最大面积
2.2.2 原理
为什么上述流程能够找到最优解呢?
接下来就证明这种方案的合理性。
首先假设头尾指针相距为 t t t,并且假设 h e i g h t [ h e a d ] < h e i g h t [ t a i l ] height[head]<height[tail] height[head]<height[tail],则面积
a r e a = t × h e i g h t [ h e a d ] area=t×height[head] area=t×height[head]
假设移动最大者,那么 t 2 = t − 1 < t t_2=t-1<t t2=t−1<t,因为高取决于两边的最短边,因此
因此新的高 h t 2 h_{t_2} ht2必然是 ≤ h e i g h t [ h e a d ] ≤height[head] ≤height[head]的,所以新的面积
a r e a 2 = t 2 × h t 2 ≤ a r e a area_2=t_2×h_{t_2}≤area area2=t2×ht2≤area.
所以可以看出,移动两者中的最长者必然会导致面积变小;同时也可以进一步想到,无论这个尾指针怎么往内部移动,都不会找到一个更大面积的情况。
也就是说以这个最左边为一边的除了当前 a r e a area area这个情况外的其它情况都不可能是最优解。
所以我们需要记录当前的面积,并移动最左边的指针。
也就是移动最长边必然会导致更小或者不变,移动最短边则有可能会变好。
通过不断的这样筛选的过程,我们其实仍然是遍历了所有可能,只不过那些被淘汰的是隐式地。
2.2.3 代码
def myAtoi(s: str) -> int:
n = len(height)
head = 0
tail = n - 1
# 分别对比左右指针指向的数,最大的一方指针保持不懂,另一方向中间移动
max_area = 0
while head != tail:
if height[head] > height[tail]:
area = (tail - head) * height[tail]
tail -= 1
else:
area = (tail - head) * height[head]
head += 1
max_area = max(max_area, area)
return max_area
对于时间复杂度,因为首尾指针合在一起指向了所有数组的数,所有时间复杂度为 O ( N ) O(N) O(N)
空间复杂度, O ( 1 ) O(1) O(1)