【leetcode】 盛最多水的容器

一、题目描述

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

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

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

说明:你不能倾斜容器。

在这里插入图片描述

输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组
[1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

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

二、代码思路

分析题目,我们知道题目的意思是让我们求出两条棒子围出的最大面积,围出的面积是由短杆的高度乘与底边长得到的,也就是:

int area = (right - left) * Math.min(height[left], height[right]);

有两种解题方法

2.1 暴力题解

上面已经解释过了,目的是计算两条杠围成的最大面积,那么我们枚举出所有两条杠的组合即可。

2.2 双指针

上述的暴力题解,时间复杂度较高,题目要求n<10^5, on2的时间复杂度显然会超时的。所以想想优化的解法,题目中提到了左右两条杠组成的面积,所以我们可以考虑到双指针的解题思路。

但是问题的难点是双指针如何移动,我们考虑题目的要求,要求面积最大,面积是由左右杠高度以及左右杠之间的距离决定的,所以,移动规则如下:

  • 如果left杠高度大于right杠那么移动right杠,也就是移动高度低的。
  • 如果两条杠高度一致移动任意一个。
  • 如果移动的时候发现相邻的杠高度比自身高度还低,那么不用计算其围成的面积。(因为底边长度度变少了,高度也变少了,那么面积必然也会变少)

那么如何证明我们移动的是正确的呢?

如果left杠高度大于right杠那么移动right杠,也就是移动高度低的。为什么移动高度低的? 计算面积的时候是由高度低的决定的面积,如果不移动它,那么面积会一直受到其限制,这样造成的结果就是底边越来越短,高度不变,或者高度变得更低。所以,移动高度高的我们的面积只会越来越短,从而做一些没必要的计算,只有移动高度低的才有可能出现面积更大的元素。

考虑第一步,假设当前左指针和右指针指向的数分别为 x 和 y,不失一般性,我们假设 x≤y。同时,两个指针之间的距离为 t。那么,它们组成的容器的容量为:

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

我们可以断定,如果我们保持左指针的位置不变,那么无论右指针在哪里,这个容器的容量都不会超过 x∗tx * tx∗t 了。注意这里右指针只能向左移动,因为 我们考虑的是第一步,也就是 指针还指向数组的左右边界的时候。

详细题解:https://leetcode.cn/problems/container-with-most-water/solutions/207215/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/

三、代码题解
package leetcode.lc20221204;

/*
 * @author lzy
 * @version 1.0
 * @DESC 乘最多水的容器
 * */
class Solution01 {
    public static void main(String[] args) {

    }
    //思路1 :暴力解决
    //时间复杂度:o(n2) 2 <= n <= 10^5 会超时
    //空间复杂度:o1
    public int maxArea1(int[] height) {
        int res = 0;
        //边界值处理
        int length = height.length;
        if (length == 2) {
            return length * Math.min(height[0], height[1]);
        }
        //处理其他值,枚举出任意两根棒子组成的面积
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                int area = (j - i) * Math.min(height[i],height[j]);
                res = area > res ? area : res;
            }
        }
        return res;
    }
    //思路2:双指针问题
    public int maxArea(int[] height) {
        int res = 0;
        //边界值处理
        int length = height.length;
        if (length == 2) {
            return length * Math.min(height[0], height[1]);
        }
        int left = 0;
        int right = length - 1;
        while (left < right) {
            int area = (right - left) * Math.min(height[left], height[right]);
            res = area > res ? area : res;
            if (height[left] > height[right]) {
                right--;
            } else {
                left++;
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值