LeetCode 热题 HOT 100 Java题解——11. 盛最多水的容器

LeetCode 热题 HOT 100 Java题解

11. 盛最多水的容器

题目:
给你 n n n 个非负整数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1a2...an,每个数代表坐标中的一个点  ( i ,   a i ) (i, a_i) (i, ai) 。在坐标内画 n n n 条垂直线,垂直线 i i i 的两个端点分别为  ( i ,   a i ) (i, a_i) (i, ai) ( i , 0 ) (i, 0) (i,0)。找出其中的两条线,使得它们与  x x x 轴共同构成的容器可以容纳最多的水。

说明: 你不能倾斜容器,且  n n n 的值至少为 2 2 2

avatar

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

示例:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

双指针

本题非常关键的一点就是两个指针 i i i j j j所构成的面积 S = M a t h . m i n ( h e i g h t [ i ] , h e i g h t [ j ] ) ∗ ( j − i ) S = Math.min(height[i], height[j]) * (j - i) S=Math.min(height[i],height[j])(ji),面积是由 x x x轴长度和两个指针指向的垂直线中短的那根所决定的。

因此,我们将两个指针放在两端开始向内收缩,由于 j − i j - i ji是一定变小的,所以我们考虑收缩哪个指针,如果收缩的是指向垂直线长的那个指针,则面积一定是会不变或变小的,而若我们收缩短的那个指针,则面积是有可能变大的,抓住这点,我们每次都可以通过比较两个指针指向垂直线的长短,来决定唯一移动一个指针,这样就把复杂度从 O ( n 2 ) O(n^2) O(n2)降到了 O ( n ) O(n) O(n)了。

class Solution {
    public int maxArea(int[] height) {
        int i = 0, j = height.length - 1;
        int max = 0;
        while(i < j) {
            max = Math.max(Math.min(height[i], height[j]) * (j - i), max);
            if (height[i] < height[j]) i++;
            else j--;
        }
        return max;
    }
}

这样的答案时间为4ms,有一个小优化在于:
如果短的那个指针收缩之后指向的垂直线没变或更短了,则没有必要计算面积,可以直接继续收缩,可以通过循环来减少计算面积的次数。

class Solution {
    public int maxArea(int[] height) {
        int i = 0, j = height.length - 1;
        int max = 0;
        while(i < j) {
            max = Math.max(Math.min(height[i], height[j]) * (j - i), max);
            if (height[i] < height[j]) {
                int left = height[i];
                while(i < j && height[i] <= left) i++;
            }
            else {
                int right = height[j];
                while(i < j && height[j] <= right) j--;
            }
        }
        return max;
    }
}

这样答案时间就减少到了2ms,击败了99%。

复杂度分析
  • 时间复杂度: O ( n ) O(n) O(n)

    两个指针收缩遍历一遍数组。

  • 空间复杂度: O ( 1 ) O(1) O(1)

    只使用常数个变量的额外空间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值