算法题:盛最多水的容器(题目+思路+代码+注释)

优于leetcode官方解法,时间3ms,超过94.33%的人,空间51.5MB,超过51.74%的人。

题目

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 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
示例 3:

输入:height = [4,3,2,1,4]
输出:16
示例 4:

输入:height = [1,2,1]
输出:2

提示:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

第一次解:超过14%的人,采用的两层循环的左右标兵法(是两层循环,对左标兵和右标兵分别进行了优化减少运算)
第二次解:受官方解的启发写的,双指针移动小的办法,如下图
在这里插入图片描述
在这里插入图片描述

代码

//第一次的解法,两层循环的左右标兵法(是两层循环,对左标兵和右标兵分别进行了优化减少运算)
    public int maxArea(int[] height) {
        //定义两个标兵,一个最左边开始,一个最右边开始,两层for循环,首先算出初始容器大小,然后右边标兵左移,左移后先拿那个位置的数和当前这轮循环的最大数判断,如果比最大数都小,就不算了直接继续往左边移动
        //对每个间距做一个数组记录每个间距的最大高度,小于最大高度则放弃
        int len=height.length;
        if (len==2){
            return Math.min(height[0],height[1]);
        }
        //左右标兵、最大值
        int left=0,right=0,leftVal,rightVal,max=0,maxRight,top,bottom,tmp;

        //左标兵 向右走
        for (;left<len;left++){
            leftVal = height[left];
            maxRight = 0;
            //左标兵开始前过滤,如果给你左边乘以你能有的最大长度你还是会比临界值低那直接不用求了
            if (max>0){
                int leftLimit = max/(len-left);
                if ( leftVal < leftLimit ){
                    continue;
                }
            }
            //右标兵向左走
            for (right=len-1;right>left;right--){
                rightVal = height[right];
                //右标兵优化
                if (rightVal < maxRight){
                    continue;
                }
                maxRight = rightVal;
                //不小于就继续
                top = Math.min(leftVal,rightVal);
                bottom =  right - left;
                tmp = top * bottom;
                if (tmp > max){
                    max = tmp;
                }
            }
        }
        return max;
    }

//受官方解法启发后写的
public int maxArea(int[] height){
        //最大面积
        int max=0;
        //特殊情况直接返回
        if (height.length==2){
            return Math.min(height[0],height[1]);
        }
        //开始计算前的变量声明  长度,左指针下标,左指针的值,右指针下标,右指针的值,临时变量存储临时面积
        int len=height.length,left=0,leftVal=height[left],right=len-1,rightVal=height[right],tmp;
        //容器面积是由底边长度乘以柱高,首先取最大长度,然后不断提升柱高,x*y,每次移动x-1,而y很可能+1以上则这个过程中遇到的会是最大面积
        //开始循环
        while (left<right){
            //计算当前左右指针形成的容器的面积
            tmp = (right-left)*Math.min(leftVal,rightVal);
            //超过历史记录就替换
            if (tmp > max){
                max=tmp;
            }
            //移动最小值
            if (leftVal < rightVal){
                leftVal=height[++left];
            }else {
                rightVal=height[--right];
            }
        }
        return max;
    }

在这里插入图片描述

posted @ 2021-04-19 14:35  HumorChen99  阅读(113)  评论(0编辑  收藏  举报  来源