最多盛水问题(双指针思想)

目录

1. 题目要求

2. 题目理解以及方法的思路

3. 程序框架

4. 代码分部讲解

C讲解:

C++讲解:


 题目要求

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

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

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

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

提示:

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

来源:力扣(LeetCode)

 这个题目很多读者乍一看不知道从何处下手,想了很多方法和思路,比如“动态规划”“for循环”等等。这些方法和思路都可以完成这道题目,但是今天我们来讲解一个最简单的方法——“双指针”。这道题我们分别用 C/C++ 来进行讲解。

题目理解以及方法的思路

(一)首先呢,我们先来理解这个题目,看看它到底要我们干什么?其实就是实际生活中的盛水问题,也就是一些老师和家长常说的“木桶定律”——一个木桶能装多少水取决于其最短的那个木板。

明白这些后,我们接着往下讲。什么是“双指针”? 为什么用“双指针”?

“双指针”就是用两个指针分别指向左右两边的“木板”上,通过移动双指针的位置来实现改变木板的底部长度的目的。那么问题来了,这样做凭什么保证某个位置盛水量最大呢?因此,我们仅仅只是定义双指针还不行,还必须有一套指针移动的规律,使其按着这个规律去求,最终可以遍历所有的可能,并且求出盛水量最大的位置。

盛水量 = 两个指针指向的数字中较小值 * 指针之间的距离

(二)前面我们讲了“木板定律”,明白了盛水量取决于最短的那个木板的高度。因此在这里,我们先进行比较。比较什么呢? 我们就比较此时两个指针指向的左右两边对应的数字的大小,假设左边对应的是 L ,右边对应的是 R 。即 如果 L>R ,则右指针左移;如果 L<R ,则左指针右移。

这个时候有的读者仍会有疑问,不明白为什么指针这样移动。其实很简单,我们先列一个式子,假设当前左指针和右指针指向的数分别为 x 和 y ,不失一般性,我们假设是 x < y。同时,两个指针之间的距离为 t 。那么,它们组成的容器的容量为:

min(x,y)∗t=x∗t

因此我们可以断定,如果我们保持左指针的位置不变,那么无论右指针在哪(向左移动),这个容器的容量都不会超过 x * t 。(木桶定律)

(三)明白上面的内容后,我们接着继续。

我们是通过不断减小两个指针间的距离来遍历的,很显然当两指针间的距离减小时,要想使其容量最大,我们必须使得最短的那个“木板”最大才有可能。因此就决定了每次移动指针的规律是那边的最小我们在下一次判断时便移动哪一边的指针。(从而也证明此处在程序中需要设立一个“判断”)

程序框架

到此,我们对整个题目的分析也就结束了,下面我们通过对上面的理解,来对整个程序的框架进行整理:

1.比较:左右两指针对应的数字的大小,取最小的值带入求出容量。(至于为什么取最小值,参考前面的分析以及“木桶定律”)

2.比较:拿每一次指针移动后的值与移动前的值进行比较,取最大值。

3.判断:判断左右两指针对应的数字的大小,从而决定下一次哪个指针移动。

代码分部讲解

接下来我们便开始代码的分部讲解:我们分为 C 和 C++ 两个大类。

C讲解:

int maxArea(int* height, int heightSize){
    int l = 0;   //初始化,使左指针指向数据的最左边
    int r = heightSize - 1;  //使右指针指向数据的最右边
    int temp,V = 0;   //初始化体积
    while(l<r)   //循环,当右指针与左指针重合时循环结束
      {
        temp = ((height[l]<=height[r])?height[l]:height[r])*(r-l); //取左右指针对应数字中最小 
                                                                   //的,求其此时的体积。
        V = (V>=temp)?V:temp;  //三目运算符进行比较
        if(height[l] <= height[r])  //判断,哪边小,则下一次便移动那一边的指针
          ++l;
        else
          --r;
      }
    return V;  //返回体积 V
}

接下来对一些地方着重讲解一下:

( height[l] <= height[r] ) ? height[l] : height[r]  //取最小值

V = (V>=temp) ? V : temp  //取最大值

这两个是三目运算符,可以减少冗长的比较步骤

其作用就相当于: 

if(height[l] <= height[r])

     temp = height[l]*(r-l);

else

     temp = height[r]*(r-l);

if(temp >= V)

     V = temp;

else

     V = V;

C++讲解:

class Solution {
public:
    int maxArea(vector<int>& height) {
    int l = 0;
    int r = height.size() - 1;
    int temp,V = 0;
    while(l<r)
      {
        temp = min(height[l], height[r])*(r-l);
        V = max(V,temp);
        if(height[l] <= height[r])
          l++;
        else
          r--;
      }
    return V;

    }
};

可以看出 C++ 和 C 很相似,就不再过多的讲解了,其中有不同的地方。

min ( height[l] ,  height[r] )

V = max ( V , temp )

C++ 里尤其专门的比较最大最小的方法,也比 C 更好理解。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

简十三

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

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

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

打赏作者

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

抵扣说明:

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

余额充值