thinkbuzan的博客

thinkbuzan的博客

【高级编程技术】【作业】【第八周】【3】

LeetCode练习题

11. 盛最多水的容器

描述

给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。画 n 条垂直线,使得垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
注意:你不能倾斜容器,n 至少是2。

思路

首先尝试了一下n2枚举,意料之中地超时了。然而并没有什么好的想法,不过看到题目的标签上提示了双指针,于是就去查了一下,发现这题是用头尾两个指针往中间移动的方式来枚举容器的两边,这样算法复杂度是O(n),需要优先移动高度较矮的一端,我看到的解释是这样的:

当逐渐逼近的时候,容器的长在变短,那么要使得面积增大的话,宽必须要变大,所以我们保留长的那条线段,使得短线段向另一方逐渐逼近。

嗯……好像挺有道理,从直观上看挑不出什么毛病,至少照这个样子写出来的代码A了。这之后我经过思考认为这个方法应该是正确的。

下面想从反面的角度说明一下这种做法的正确性。水的多少取决于矮边和底边,如果优先移动高度较长的一端的话,接下来的所有的尝试是不会获得比当前状态更好的结果的(矮边没变,长度变短,长边再长也没用),因此移动短边是合理的

那么有没有可能会错过答案呢?有没有可能在答案的一边指到的时候,另一边的指针已经指过了呢?我们需要想到这样一个性质,就是答案的两边的外侧都比矮边更矮

答案示意图

可以很容易用反证法证明。那么在移动指针的时候,无论是先到高边还是先到矮边,答案的外侧都没有边可以使得在另一边还没有指到的情况下就继续往内侧移动(有点拗口),换句话来说,当答案的其中一条边被指到的时候,这个指针看起来就好像在等待另一边一样,直到另一边也被指到!所以这个方法是正确的,答案不会被错过

代码

class Solution:
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        ans = 0
        p = 0
        q = len(height)-1
        while p < q:
            ans = max(ans, (q-p)*min(height[p], height[q]))
            if height[p] < height[q]:
                p += 1
            else:
                q -= 1
        return ans
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

【高级编程技术】【作业】【第八周】【3】

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭