盛最多水的容器(双指针)

文章讲述了如何使用双指针方法解决给定整数数组表示的水槽问题,通过不断调整两端高度,找到可以容纳最多水的容器。算法通过比较两板高度,逐步缩短短板,直至双指针相遇。优化后的代码具有O(N)的时间复杂度和O(1)的空间复杂度。
摘要由CSDN通过智能技术生成

问题

给定一个长度为 n 的整数数组 height 。

 n 条垂线,第 i 条线的两个端点是 (i,0) 和 (i,height[i]) 。

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

说明:你不能倾斜容器。

问题分析

设两指针i,j  ,指向的水槽板的高度分别为H[i],H[j],此状态下水槽面积为S(i,j ).

由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :

S(i,j) = min(H[i],H[j]) * (j-i)

无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1,变短:

  • 若向内移动短板,水槽的短板min(H[i],H[j])可能变大,因此下个水槽的面积可能增大
  • 若向内移动长板,水槽的短板min(H[i],H[j])不变或变小,因此下个水槽的面积一定变小

因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出,即可获得最大面积。

算法流程

  1. 初始化双指针i,j分别指向水槽两边。
  2. 更新最大面积,选择两板中较短的板子向中间收窄一格,重复至两针相遇时跳出。
  3. 返回最大面积。

代码

int maxArea(vector<int>& height) {
    int i = 0; // 左边界
    int j = height.size() - 1; // 右边界
    int maxArea = 0; // 最大面积

    while (left < right) {
        int minHeight = min(height[left], height[right]); // 找到当前两根柱子中的较短柱子
        int res= (right - left) * minHeight; // 计算当前区域的面积
        maxArea = max(maxArea, res); // 更新最大面积

        // 移动较短柱子的指针,以寻找可能更大的面积
        if (height[i] < height[j]) {
            i++;
        } else {
            j--;
        }
    }

    return maxArea;
}

以上代码可优化如下:

int maxArea(vector<int>& height) {
            int i = 0,j = height.size()-1,res = 0;
            while(i<j)
            {
                res = height[i] < height[j] ?
                    max(res,(j-i) * height[i++]):
                    max(res,(j-i) * height[j--]);
            }
            return res;

复杂度分析

  • 时间复杂度O(N):双指针遍历一次底边宽度N​​。
  • 空间复杂度O(1)​ :变量 i,j,res使用常数额外空间。

Q&A

双指针相等 的情况下,移动不同的值是否有可能错过最大面积?

答:不会。

i和j的高度是相同的,而面积最大值取决于短边;当i和j的高度相同时,移动任何一边,如果变矮了,那面积会变小;如果变高了,面积也不会变大。而下一次移动的时候面积才会发生变化。也就是说i和j都必须往里缩小一次才有可能出现更大的面积。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值