【Leetcode面试常见题目题解】4. 盛最多水的容器

文章介绍了LeetCode第11题的解题思路,即如何找到两个高度值,使它们与x轴形成的容器能容纳最多的水。采用双指针方法,从数组两端开始,每次移动较矮边的指针,计算并更新最大面积。文章提供了两种双指针解法,一种是基础实现,另一种尝试进行优化,但强调应优先选择清晰易懂的实现方式。
摘要由CSDN通过智能技术生成

题目描述

本文是LC第11题:盛最多水的容器。
题目描述如下:

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。

限制

n == height.length
2 <= n <= 105
0 <= height[i] <= 104

示例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

解题思路

  • 暴力解法
  • 双指针
    有句话:你的能力取决于你的短板。这句话的来源正是水桶问题,一个有一面短板的水桶最多的盛水量由短板的高度决定。(水桶上下半径是确定的)
    对于本题,容器的盛水量取决于两个因素——容器的底和容器较短的那条高。 容器高度较大的一侧的移动只会造成容器盛水量减小,所以应当移动高度较小一侧的指针,并继续遍历,直至两指针相遇 。

假设有左指针 left 和右指针 right ,且 left 指向的值小于 right 的值,如何移动双指针才能保证最大的盛水量被遍历到,假如我们将右指针左移,则右指针左移后的值和左指针指向的值相比有三种情况:

右指针指向的值 > 左指针(指向的值),容器的高取决于左指针,但是底变短了,所以容器盛水量一定变小;
右指针指向的值 == 左指针(指向的值),容器的高取决于左指针,但是底变短了,所以容器盛水量一定变小;
右指针指向的值 < 左指针(指向的值),容器的高取决于右指针,但是右指针小于左指针,且底也变短了,所以容量盛水量一定变小了.

代码

双指针解法

class Solution {
public:
    int maxArea(vector<int>& height) {
        int maxArea = 0; // 注意水位有可能是0,因此最小面积为0
        int i = 0; // 左指针
        int j = height.size() - 1; // 右指针
            
        while ( i < j ) { // 循环直到左右指针相遇
            maxArea = max(maxArea, (j-i)*min(height[i], height[j]));  // 记录最大面积,与当前i,j围成的面积比较
            if ( height[i] < height[j]) { // 移动指向较小值的指针
            	++i;
            } else { 
            	--j;
            }
    
        }
        return maxArea;
    }
};

双指针优化解法:上述第一版代码其实是不断移动较小的指针,然后计算当前围成的面积,当当前围成的面积 > 最大面积时,更新最大面积,然后继续直到 i >= j。
因此也可以采用如下这种代码写法,语义为 “记录下当前较小值,移动指向较小值的那个指针,直到指针指向的值 > 记录的较小值”,其实就是一次性多跳几个比当前值还小的的值,省去了几次计算面积的开销。
但这样的写法不建议使用,代码虽然优化了,但优化力度甚至可以忽略。
在写算法实现的时候,一定要记住:有思路,有最简单易懂的实现可以解决问题的时候,不要再去花过多的时间绞尽脑汁的在一些优化度不高的点上优化。因为即便写出了如下的代码,别人也未必能一眼看懂。而且还消耗了自己的时间。

class Solution {
public:
    int maxArea(vector<int>& height) {
        int maxArea = 0; // 注意水位有可能是0,因此最小面积为0
        int i = 0; // 左指针
        int j = height.size() - 1; // 右指针
            
        while (i < j) { // 循环直到左右指针相遇
            int h = min (height[i] , height[j]); // 记录下当前较小值
            maxArea = max (maxArea, (j-i) * h); 
            // h 是 height[i] , height[j] 中的一个,所以以下两个循环只执行其中一个
            while(i < j && height[i] <= h) ++i; 
            while(i < j && height[j] <= h) --j;
        }
        return maxArea;
    }
};

补上这段代码实际做的事:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

csdnGuoYuying

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

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

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

打赏作者

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

抵扣说明:

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

余额充值