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

LeetCode练习题

11. 盛最多水的容器

描述

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

思路

首先尝试了一下 n2 n 2 枚举,意料之中地超时了。然而并没有什么好的想法,不过看到题目的标签上提示了双指针,于是就去查了一下,发现这题是用头尾两个指针往中间移动的方式来枚举容器的两边,这样算法复杂度是 O(n) 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值