【力扣刷题】【1-50】11. 盛最多水的容器

11. 盛最多水的容器

1.暴力枚举

  • 最容易想到直接暴力枚举,会进行 C n 2 C_{n}^{2} Cn2 次枚举,面积运算公式为$S=(r-l)*min( h[l],h[r] ) $、时间复杂度O(n2);

  • 这里的代码会超时,但是会帮助我们下面对于双指针的理解。

  • 如下图,以有八根木棍为例,事实上我们只进行了(8*8)/2次的计算.

  • 在这里插入图片描述

    class Solution {
    public:
        int maxArea(vector<int>& height) {
            int n=height.size();
            int result=0;
            for(int i=0;i<n;i++){
                for(int j=i;j<n;j++){
                    int area=min(height[j],height[i])*(j-i);
                    result=max(result,area);
                }
            }
            return result;
        }
    };
    

2.双指针法

  • 这里我们可以使用双指针法,从左右两端不断向内收缩,时间复杂度O(n)得出结果:

    • 方法:初始左指针l=0,r=n-1;每次向内移动h[l],h[r]中较小的那一个;
  • 难点:双指针法的写法也很简单,问题的关键是我们要证明双指针法的正确性,这里力扣的官方题解我认为有瑕疵;

  • 官方题解给出的部分其实也很好理解:

    对于l,r中较短的那一侧,我们假设此时l是高度较短的那一侧:

    1.无论另一侧的r怎么向内移动,min[h[l],h[r]]都不会比当前的数值更大了,因为当前的l就是“短板效应”里最短的那根板;

    2.而(r-l)因为双侧指针是不断向内移动的,(r-l)也只会越变越小;

    3.因此当前的min[h[l],h[r]]*(r-l)就已经是当前这个位置的 l 可以取得的最大值了;

    我们将这个值与结果进行比较取最大值后,抛弃这一个较短的一侧,向内移动后再进行比较。

  • 这里分析的问题在于,忽视了l和r靠外的两侧会出现更大结果的可能性;

    就上例而言,l是高度较短的一侧,却只允许r向内移动,难道向外移动就不会有更大的结果吗?

    ———————————————————————————————————————————————

  • 对这个问题,需要根据每次比较对搜索空间减小的作用来分析。

    我们需要搜索的空间如暴力枚举中的图片一样,需要进行(n*n)/2次检查,但是每次排除短端都能将搜索空间减小一行或者一列,而暴力枚举每次只能排除一个

    我们假设第一次左侧l=0是较短的一端,无论r在搜索空间内的哪个位置,l=0可能的最大面积我们可以通过上面的公式一步计算出来。我们再将其排除,事实上是排除了l=0作为最终答案的所有可能:如下图:

    此时新的搜索空间就是由新的[l,r]构成的新的倒三角,l,r两端外侧的可能性都被排除了,因此,双指针法只需要不断向内移动的正确性得以证明

    在这里插入图片描述

  • 我们再模拟一步,如果是右侧r是端端被排除,搜索空间被缩小了一列,新的搜索空间将r右侧是最终答案的可能性彻底排除:

    在这里插入图片描述

    class Solution {
    public:
        int maxArea(vector<int>& height) {
            int n=height.size();
            int result=0;
            int l=0,r=n-1;
            while(l<r){
                int area=min(height[l],height[r])*(r-l);
                if(height[l]<=height[r]){
                    l++;
                }else{
                    r--;
                }
                result=max(result,area);
            }
            return result;
        }
    };
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值