LeetCode 11-盛最多水的容器

146 阅读3分钟

题目

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明: 你不能倾斜容器。

image.png

思路

单调栈(暂无解)

最开始想的是用单调栈来解答这道题,从栈底到栈顶依次递减,遇到大于栈顶的就弹出,更新结果res,最后再清算栈内的元素,但是这样做出来,覆盖不了全部数据。后面又想到了2个栈进行弹出,一个栈顶到栈底依次递减,一个栈顶到栈底依次递增,但是后面写出来了,发现中间如果在中间某处破坏了单调性,导致更新的res不是最大的值。后面有时间再想想这个,看看有没有机会写出来。

暴力解法-两重循环

通过两个for循环,找到所有的面积,然后取最大面积。 时间复杂度:O(N^2),空间复杂度:O(1)

代码一-暴力双循环

class Solution:
    def maxArea(self, height: List[int]) -> int:
        i = 0
        res = 0
        n = len(height)
        for i in range(n):
            for j in range(i+1, n):
                res = max(res, min(height[i], height[j])*(j-i))
        return res

双指针-移动短边

需要移动两头问题,可以考虑双指针。

难点:如何移动指针?

  • 相同情况下,两边距离越远越好
  • 区域受限于较短边

距离越远越好,所以右指针从最右开始,保证宽度达到最长; 在向左(向右)扫描时,如果右边(左边)比较短或者和原来的一样长,可以跳过面积的计算,因为原来宽度和高度更大,所以现在面积只会更小。

如何决定移动左指针还是右指针?

考虑第二特性,区域受限于较短边,如果右边比左边长,那么我们应该移动左指针,保留右指针,因为短的边限制了面积增大可能性,移动左指针只会导致宽度变小,寻找更好的左指针点。反之同理。

左右指针分别从头尾出发,每次只固定较长的边的指针,短边指针向内移动,计算该边变长后的面积,同时决定是否要交换移动顺序。

代码二:双指针-简洁版

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

代码三:双指针-优化版

将下面这段话加入代码: 在向左(向右)扫描时,如果右边(左边)比较短或者和原来的一样长,可以跳过面积的计算,因为原来宽度和高度更大,所以现在面积只会更小。

每次移动指针的时候,通过判断找到左边or右边下一个更大的高度,避免res的重复计算,减少计算量。

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