LeetCode高频题11:盛最多水的容器

LeetCode高频题11:盛最多水的容器

提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
在这里插入图片描述


文章目录

  • LeetCode高频题11:盛最多水的容器
    • @[TOC](文章目录)
  • 题目
  • 一、审题
  • 笔试面试最优解!o(n)复杂度快速通过
  • 其他解法代码:o(n^2)复杂度,笔试通不过,面试得0分
    • 暴力解:
    • 暴力2
  • 总结

题目

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

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

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

说明:你不能倾斜容器。

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


一、审题

示例 1:
LeetCode高频题11:盛最多水的容器_第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


笔试面试最优解!o(n)复杂度快速通过

根据短板理论,短板才是水桶水位最高的地方,超过这个短板高度,水漏了
LeetCode高频题11:盛最多水的容器_第2张图片
题意其实你应该很好理解
说白了下图
arr=4 8 6 4 6 4 8
依次给你水桶的板高
你需要任选两个板,来组成一个水桶,装水
LeetCode高频题11:盛最多水的容器_第3张图片
(1)你可以选择绿色两块板,则水高为4,底边长5-4=1,故水量是41=4
(2)你可以选择粉色两块板,则水高为4,底边长5-3=2,故水量是4
2=8
(3)你可以选择橘色两块板,则水高为8,底边长6-1=5,故水量是8*5=40
最后取max就行

这就是本题的意思

显然两块板,就需要双指针搞定
L,R一个在左,一个在右,相当于在看每次地边a最大的情况下,咱们去看看哪些板子最高,越高越好,整最大值
(1)当L小时,短板(瓶颈)就是L,R不动(因为R不是瓶颈,而且此时R距离L最远,a底边最大),
结算水量,然后L++,探索L还有更高的板子吗?
LeetCode高频题11:盛最多水的容器_第4张图片

(2)与(1)对称的,当R小时,短板(瓶颈)就是R,L不动(因为L不是瓶颈,而且此时R距离L最远,a底边最大),
结算水量,然后R–,探索R还有更高的板子吗?
LeetCode高频题11:盛最多水的容器_第5张图片

(3)当L=R时,俩都是瓶颈,而且此时R距离L最远,结算水量,可以任意让L++,R–,探索有没有更高的LR板子?
中途结算水量,全部更新给max,以获取底边a最大情况下,桶组合最大的水量。【这点其实左神根本就没讲清楚,我自己理解才能捋清】

这么搞的话,LR从两头往中间凑,一定在考虑a最大的情况下,两根板子尽可能高的最优解先更新给max了
比如下图
对于0这个高度8
从R=N-1往左走,不断遇到7777 10
对于与L=0的那个板子,跟它组合的水桶中
那么8–10桶是最优解吗?
不是

因为最开始a最长的时候,8–7这个桶已经是最优解了,中途max遇到8–10这个桶是不会更新的。
LeetCode高频题11:盛最多水的容器_第6张图片
其实手撕代码就非常容易了
上面三个条件,三进一
沿途收集max水量

注意两个板子之间的空隙就是1单位

        //复习:
        //根据短板理论,短板才是水桶水位最高的地方,超过这个短板高度,水漏了
        public int maxWater(int[] arr){
            if (arr == null || arr.length < 2) return 0;//没法组合桶
            //L,R一个在左,一个在右,**相当于在看每次地边a最大的情况下**,咱们去看看哪些板子最高,越高越好,整最大值
            int L = 0;
            int R = arr.length - 1;//边界,此时地板a最大
            int max = 0;//水量
            while (L < R){//L=R时,a=0,不要
                //中途结算水量,全部更新给max,以获取底边a最大情况下,桶组合最大的水量。
                int a = R - L;//不算RL位置,中间扣自然就是1单位长度
                int height = Math.min(arr[L], arr[R]);
                max = Math.max(max, a * height);//结算
                //(1)当L小时,短板(瓶颈)就是L,R不动(因为R不是瓶颈,而且此时R距离L最远,a底边最大),
                //结算水量,然后L++,探索L还有更高的板子吗?
                if (arr[L] < arr[R]) L++;
                //(2)与(1)对称的,当R小时,短板(瓶颈)就是R,L不动(因为L不是瓶颈,而且此时R距离L最远,a底边最大),
                //结算水量,然后R--,探索R还有更高的板子吗?
                else R--;//23俩条件共用了
                //(3)当L=R时,俩都是瓶颈,而且此时R距离L最远,结算水量,可以任意让L++,R--,探索有没有更高的LR板子?
            }

            return max;
        }

核心思想就是:
LR从两头往中间凑,一定在考虑a最大的情况下,两根板子尽可能高的最优解先更新给max了

    public static void test(){
//        int[] arr = {1,2};
        int[] arr = {1,8,6,2,5,4,8,3,7};
        Solution solution = new Solution();
        System.out.println(solution.maxArea3(arr));
        System.out.println(solution.maxWater(arr));
    }

    public static void main(String[] args) {
        test();
    }
49
49

去LeetCode测试一把:

class Solution {
    public int maxArea(int[] height) {
//根据短板理论,短板才是水桶水位最高的地方,超过这个短板高度,水漏了
            if (height == null || height.length < 2) return 0;//没法组合桶
            //L,R一个在左,一个在右,**相当于在看每次地边a最大的情况下**,咱们去看看哪些板子最高,越高越好,整最大值
            int L = 0;
            int R = height.length - 1;//边界,此时地板a最大
            int max = 0;//水量
            while (L < R){//L=R时,a=0,不要
                //中途结算水量,全部更新给max,以获取底边a最大情况下,桶组合最大的水量。
                int a = R - L;//不算RL位置,中间扣自然就是1单位长度
                int h = Math.min(height[L], height[R]);
                max = Math.max(max, a * h);//结算
                //(1)当L小时,短板(瓶颈)就是L,R不动(因为R不是瓶颈,而且此时R距离L最远,a底边最大),
                //结算水量,然后L++,探索L还有更高的板子吗?
                if (height[L] < height[R]) L++;
                //(2)与(1)对称的,当R小时,短板(瓶颈)就是R,L不动(因为L不是瓶颈,而且此时R距离L最远,a底边最大),
                //结算水量,然后R--,探索R还有更高的板子吗?
                else R--;//23俩条件共用了
                //(3)当L=R时,俩都是瓶颈,而且此时R距离L最远,结算水量,可以任意让L++,R--,探索有没有更高的LR板子?
            }

            return max;
        }
}

LeetCode高频题11:盛最多水的容器_第7张图片
还可以吧?
复杂度:
每一次不是L++,就是R–,L=R碰面停止,整体就遍历一次,N个走完max就出结果,o(n)复杂度

其他解法代码:o(n^2)复杂度,笔试通不过,面试得0分

暴力解:

每一个位置i去看看后面所有板子的位置j,形成的水桶,哪个好,更新给max

        //暴力解
        public int maxArea(int[] height) {
            //暴力解:o(n^2)
            //每个位置i,其他位置j都过一遍
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < height.length; i++) {//暴力解,可能在测试时直接挂了,超出了时间限制
                for (int j = i + 1; j < height.length; j++) {
                    max = Math.max(max, (j - i) * Math.min(height[i], height[j]));
                }
            }

            return max;
        }

暴力2

每一个位置i的桶,做瓶颈,其他位置j没有我高的不看,去找更远,更高的桶

        public int maxArea2(int[] height) {
            //优化暴力:o(n^2)
            //每个位置i做一次最低的桶沿,遍历真个数组,如果其他j都还没我高,不管了,否则就乘一遍,
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < height.length; i++) {
                for (int j = 0; j < height.length; j++) {
                    if (j != i && height[j] >= height[i])
                        max = Math.max(max, Math.abs(j - i) * height[i]);
                    //跳过大量的低桶--没用还是o(n^2)
                }
            }

            return max;
        }

暴力解代码可以不看
主要看上面的最优解


总结

提示:重要经验:

1)LR从两头往中间凑,一定在考虑a最大的情况下,两根板子尽可能高的最优解先更新给max了
2)当L小,让L探索有没有更高的瓶颈,R也类似,总之保证底边a最大的可能性下,去探索更高的瓶颈,这样算出来的水量是最好的
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

你可能感兴趣的:(大厂面试高频题之数据结构与算法,leetcode,水量,盛最多的水量,水桶短板理论,双指针LR)