题目
给定一个长度为 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
提示:
n == height.length2 <= n <= 1050 <= height[i] <= 104
解题思路
最初的方法 是采用了双指针策略,即设置两个指针分别指向数组的首尾,然后向中间移动,每次移动较短的线段指针,并更新最大面积。
最初的代码
class Solution:
def maxArea(self, height: List[int]) -> int:
left, right = 0, len(height) - 1
max_water = 0
while left < right:
# 计算当前容器的水量
water = (right - left) * min(height[left], height[right])
max_water = max(max_water, water)
# 移动较短的线段
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_water
优化方法
尽管双指针法已经很有效,但我们可以通过减少某些操作来优化这个解法。例如,减少对 min 函数的调用,并直接在比较时计算面积,这样可以减少每次迭代的计算量。
运行优化后的代码
class Solution:
def maxArea(self, height: List[int]) -> int:
left, right = 0, len(height) - 1
max_area = 0
while left < right:
# 减少函数调用,直接在这里比较
if height[left] < height[right]:
area = height[left] * (right - left)
left += 1
else:
area = height[right] * (right - left)
right -= 1
if area > max_area: # 减少不必要的赋值操作
max_area = area
return max_area
运行
print(maxArea([1,8,6,2,5,4,8,3,7])) # 应输出 49
总结
在解决 "盛最多水的容器" 问题时,我们从一个基于双指针的基础实现出发,进行了优化以提高代码执行效率。
优化前的实现: 初始解法利用了双指针法,指针分别从数组的两端向中间移动,每次迭代都计算由两个指针形成的容器的容量,并更新最大值。关键代码如下:
area = min(height[left], height[right]) * (right - left)
这个实现简洁明了,但每次迭代都要调用 min 函数来计算两个指针所指高度的最小值,这会导致不必要的重复计算。
优化后的实现: 在优化版本中,我们避免了调用 min 函数,而是通过比较指针所指的两个高度,直接进行计算:
if height[left] < height[right]:
area = height[left] * (right - left)
left += 1
else:
area = height[right] * (right - left)
right -= 1
这种方法减少了函数调用,直接在条件判断中计算宽度和高度。
优化前后的对比: 优化后的实现在执行时间上更为高效,尤其是在涉及大数据量的情况下,每次迭代避免了额外的函数调用,减少了执行时间的常数因子。虽然时间复杂度在理论上保持不变,仍为 O(n),但在实际运行中,优化后的代码更快,因为它执行更少的操作并拥有更高的操作效率。在极端情况下,这种细微的优化可能会带来显著的性能提升。