返回

LeetCode 11 容器最多能装多少水:掌握双指针技巧,解锁算法之美

前端

LeetCode 11 容器最多能装多少水 (标签: 数组 难度: 困难)

题目概述

给定一个由非负整数组成的数组 height ,其中每个数字 height[i] 表示坐标中的一个点 (i, height[i])。假设在坐标系中画出 n 条垂直线,垂直线 i 的两个端点分别为 (i, height[i]) 和 (i, 0) 。请找出这些垂直线之间的最大容器,即能够装最多水的容器。

例如,给定数组 height = [1, 8, 6, 2, 5, 4, 8, 3, 7] ,则可以形成如图所示的容器。

              |
              |
              |
        __   |   __
     /  \  |  /  \
   /    \ | /    \
  /      \|/      \
 |        |        |
 |________|________|
 0  1  2  3  4  5  6  7  8

在这个示例中,最大的容器位于序号为 1 和 8 的垂直线之间,其容量为 49。

解题思路

这道题目乍看起来似乎有些复杂,但如果我们仔细分析,就会发现其中隐藏着一些有趣的规律。首先,我们可以观察到,如果要使容器的容量最大,那么它的两条边必须尽可能地长,并且它们之间的距离也必须尽可能地大。其次,容器的容量只与两条边的长度和它们之间的距离有关,与两条边的具体位置无关。

基于这些观察,我们可以得出这样一个结论:如果我们能够找到两条边,使得它们的长度之积和它们之间的距离之积都最大,那么我们就找到了容量最大的容器。

为了找到这两条边,我们可以使用双指针技巧。我们将两个指针分别指向数组的开头和结尾,然后同时向中间移动。在移动的过程中,我们将不断比较两条边的长度之积和它们之间的距离之积,并将最大值记录下来。

如果我们遇到一条边比另一条边短,那么我们就移动较短的那条边,因为这样可以增加两条边的长度之积。如果我们遇到一条边比另一条边长,那么我们就移动较长的那条边,因为这样可以增加两条边的距离之积。

我们一直移动指针,直到它们相遇为止。此时,我们找到的两条边就是容量最大的容器的两条边。

代码实现

def maxArea(height):
  """
  计算容器最多能装多少水。

  参数:
    height: 一个由非负整数组成的数组,表示每个点的坐标。

  返回:
    容器最多能装的水的容量。
  """

  # 初始化两个指针
  left = 0
  right = len(height) - 1

  # 初始化最大容量
  max_area = 0

  # 当两个指针没有相遇时,继续循环
  while left < right:
    # 计算当前容器的容量
    area = min(height[left], height[right]) * (right - left)

    # 更新最大容量
    max_area = max(max_area, area)

    # 移动较短的那条边
    if height[left] < height[right]:
      left += 1
    else:
      right -= 1

  # 返回最大容量
  return max_area


# 测试代码
height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
result = maxArea(height)
print("容器最多能装", result, "单位水。")

算法分析

  • 时间复杂度:O(n),其中 n 是数组 height 的长度。这是因为双指针技巧只需要遍历数组一次。
  • 空间复杂度:O(1),因为我们只需要几个变量来存储指针的位置和最大容量。

总结

LeetCode 11 容器最多能装多少水是一个经典的算法问题,它考察了算法设计和数据结构方面的知识。通过对这道题目的深入理解,我们不仅掌握了双指针技巧,还解锁了算法之美。在日后的编程实践中,这些知识和技巧都将对我们大有裨益。