LeetCode 11. 盛最多水的容器(Container With Most Water)

本文深入解析了盛最多水的容器问题的两种算法:暴力法和双指针法。通过实例展示了如何在给定数组中找到能构成最大水容器的两条线,并对比了两种方法的时间和空间复杂度。

在这里插入图片描述

11. 盛最多水的容器
11. 盛最多水的容器(Container With Most Water)

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

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

盛最多水的容器

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

    输入: [1,8,6,2,5,4,8,3,7]
    输出: 49

切题

算法思路:

暴力法

在这种情况下,我们将简单地考虑每对可能出现的线段组合并找出这些情况之下的最大面积。

时间复杂度: O ( n 2 ) O(n^2) O(n2) ,计算所有 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1) 种高度组合的面积。
空间复杂度: O ( 1 ) O(1) O(1),使用恒定的额外空间。
leetcode 会超时失败

双指针法

两线段之间形成的区域总是会受到其中较短那条长度的限制。此外,两线段距离越远,得到的面积就越大。
我们在由线段长度构成的数组中使用两个指针,一个放在开始(容器左边),一个置于末尾(容器右边)。
使用变量 maxareamaxarea 来持续存储到目前为止所获得的最大面积。每次移动指向较短线段的指针向较长线段那端移动一步(从两边向中间移动)。
为什要那样移动呢?
容器左边 长为A,容器右边 长为B,中间距离为 ( b − a ) (b-a) ba从两边向中间移动(容器左边更左,以及容器右边更右的情况,已经在之前计算处理过了)。当前面积为 m i n ( A , B ) ∗ ( b − a ) min(A,B) * (b-a) min(A,B)(ba),从两边向中间移动,中间距离 ( b − a ) (b-a) ba必然减少,如果存在面积更大的情况,那么只能提高min(A,B) ,只有将较短线段的指针向较长线段那端移动,才有可能存在新的A1,B1,中间距离为(b1-a1),使得 m i n ( A 1 , B 1 ) ∗ ( b 1 − a 1 ) min(A1,B1)* (b1-a1) min(A1,B1)(b1a1)更大。
详细证明
时间复杂度: O ( n ) O(n) O(n) 一次扫描
空间复杂度: O ( 1 ) O(1) O(1),使用恒定的额外空间。

边界情况:

双指针法 需要在 right < left 时结束移动,此时左右两指针已经在中间相遇

Python3 实现

暴力法

class Solution:
    def maxArea(self, height: List[int]) -> int:
    	maxarea = 0	# 最大面积
    	length = len(height)
    	for i in range(0,length):	# 一层循环,确定容器左边
    		for j in range(i+1,length): # 二层循环,确定容器右边
    			tmparea = min(height[i],height[j])*(j-i) # 计算存水容量
    			maxarea = max(maxarea,tmparea)
    	return maxarea

双指针法

class Solution:

class Solution:
    def maxArea(self, height: List[int]) -> int:
        maxarea = 0  # 最大面积
        left = 0    # 左指针
        right = len(height) - 1 # 有指针
        while right > left:
            curarea = (right - left) * min(height[left], height[right])     # 计算当前面积
            maxarea = max(maxarea,curarea)  # 最大面积
            # 下面处理 应该哪个指针向中间移动
            if height[left] <= height[right]:
                left += 1   # 更大的面积只能是left向中间移动时出现
            else:
                right -= 1  # 更大的面积只能是right向中间移动时出现
        return maxarea

GitHub链接:
https://github.com/lichangke/LeetCode
知乎个人首页:
https://www.zhihu.com/people/lichangke/
CSDN首页:
https://me.csdn.net/leacock1991
欢迎大家来一起交流学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值