2

题目
给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

image

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

解答

方法一:排序加遍历,时间复杂度O(nlogn)

从大到小排序
维护三个变量:
当前的最低高度,当前最左,当前最右
最大面积就是 当前高度 × (当前最右 - 当前最左)

class Solution:
    def maxArea(self, height: List[int]) -> int:
        x = []
        for i, n in enumerate(height):
            x.append((i, n))
        x.sort(key=lambda x:x[1], reverse=True)
        h = min(x[0][1], x[1][1])
        l = min(x[0][0], x[1][0])
        r = max(x[0][0], x[1][0])
        ans = h * (r - l)
        for i in range(2, len(x)):
            l = min(x[i][0], l)
            r = max(x[i][0], r)
            h = min(h, x[i][1])
            ans = max(ans, h * (r - l))
        return ans

方法二:双指针, 时间复杂度O(n)

这个问题的最优解有一个特点:
如果 i 和 j 位置是最大容量,则要么 “i 是 0 到 i 中高度最高的” 要么 “j 是从 j 到最后中 高度最高的”。
因为如果两个都不满足,选择这两个最高的得到的容量一定比 i,j 容量要高。

所以这样可以采取先令 i = 0, 令 j = len(height)

然后循环计算当前容量,每次循环如果 i 的高度大于 j 则 j-= 1
如果 i 的高度小于 j 则 i -= 1

记录下过程中的最大容量,就是答案。

class Solution:
    def maxArea(self, height: List[int]) -> int:
        i = 0
        j = len(height)-1
        ans = 0
        while i < j:
            ans = max(ans, (j - i) * min(height[i], height[j]))
            if height[i] < height[j]:
                i += 1
            else:
                j -= 1
        return ans

sxwxs
292 声望21 粉丝

计算机专业学生