11. 盛最多水的容器

113 阅读2分钟

11. 盛最多水的容器 - 力扣(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

思路

可以使用双指针,接下来需要讨论的是指针怎么移动的问题。如下图所示(与题中给的不一样,直接看下图就可以),开始的时候准备两个指针,各指向左右两端,向中间移动。

接下来的请带着一个问题思考:是谁在制约着水的体积。我们努力的目标应该是突破这个制约。

未命名文件-导出 (17).png

指针移动的目标就是使得水的区域变得更大,如果移动前就能明确移动后一定会变小,那还移动它干啥。只有可能变大的情况下,我们才移动。

上图所示的两条边,是指针初始时指向的两条边,其中一个高、另一个矮。

需要明确的是,无论移动哪个底边都会变小,这是毋庸置疑的。此时制约水体积的是矮的边,那就突破这个制约,矮的边不要了,移动矮的边。如果移动高的边,并不会改变矮边制约水体积的情况。因此,当边一高一矮的情况下,只有移动矮的边才可能获得更大的水体积。

当两条边同样高时,怎么移动呢?

未命名文件-导出 (18).png

事实上,当两条边同样高的时候,两条边都是水体积的制约条件。既然都制约,那么久都不要了,一起移动。

然后在移动的过程中,统计每次能获得水体积的最大值。直至两条边相遇。

代码

func maxArea(height []int) int {
    i, j := 0, len(height)-1
    res := 0
    for i < j {
        // 移动前计算一下水的体积,取最大值
        v := (j - i) * min(height[i], height[j])
        res = max(res, v)
        // 两条边一边高,同时制约水的体积,就都不要了
        if height[i] == height[j] {
            i++
            j--
        }else if height[i] < height[j]{ 
            i++
        }else{
            j--
        }
    }
    return res
}

func min(a, b int)int{
    if a < b {
        return a
    }
    return b
}

func max(a, b int)int{
    if a > b {
        return a
    }
    return b
}