美文网首页
0011. 盛最多水的容器

0011. 盛最多水的容器

作者: 蓝笔头 | 来源:发表于2021-08-13 10:15 被阅读0次

题目地址

https://leetcode-cn.com/problems/container-with-most-water/

题目描述

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

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

![11.container-with-most-water-question](https://tva1.sinaimg.cn/large/007S8ZIlly1ghlu4wyztmj30m90anwep.jpg)

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



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

题解

暴力枚举

class Solution {
    public int maxArea(int[] height) {
        int length = height.length;
        int maxArea = 0;

        // 枚举两条线 [start, end] 所有的状态
        for (int start = 0; start < length; ++ start) {
            for (int end = start + 1; end < length; ++ end) {
                int area = getArea(height, start, end);
                if (area > maxArea) {
                    maxArea = area;
                }
            }
        }

        return maxArea;
    }

    public int getArea(int[] height, int start, int end) {
        int startHeight = height[start];
        int endHeight = height[end];
        
        int minHeight = Math.min(startHeight, endHeight);
        int length = end - start;

        return minHeight * length;
    }
}

时间复杂度 O(n^2),n 为 height 数组的长度。

上述代码执行超时。

双指针

思考一下可以怎么优化呢?

getArea() 的时间复杂度是 O(1),所以不可能优化。

那么我们只能通过剪枝去掉多余的 [start, end] 状态。
哪些 [start, end] 状态是多余的呢?

(a)case 1 start1 > start0 的情况

可以得出:length[start1, end] < length[start0, end]
因此只有 height[start1] > height[start0] 时,才可能出现 area[start1, end] > area[start0, end] 的情况。

(b)case 2 end1 < end0 的情况

可以得出:length[start, end1] < length[start, end0]
因此只有 height[end1] > height[end0] 时,才可能出现 area[start, end1] > area[start, end0] 的情况。

所以我们可以通过双指针来分别移动 startend 下标,忽略不可能的状态,来达到剪枝的效果。

(c)移动 start 还是移动 end 呢?

因为不管移动 start 还是移动 endlength 都会减一。
area = length * minHeight,所以我们要移动 height 值小的一边,从而避免错过了 maxArea

完整代码如下所示:

class Solution {
    public int maxArea(int[] height) {
        int length = height.length;
        int maxArea = 0;

        int start = 0;
        int end = length - 1;
        while (start < end) {
            int area = getArea(height, start, end);
            if (area > maxArea) {
                maxArea = area;
            }

            // 移动 height 值小的
            boolean moveStart = height[start] < height[end];
            if (moveStart) {
                // 移动 start
                // 移动到下一个 height 比当前大的 start
                int tmpStart = start + 1;
                while (tmpStart < length && height[tmpStart] <= height[start]) {
                    tmpStart++;
                }
                start = tmpStart;
            } else {
                // 移动 end
                // 移动到下一个 height 比当前大的 end
                int tmpEnd = end - 1;
                while (tmpEnd > 0 && height[tmpEnd] <= height[end]) {
                    tmpEnd--;
                }
                end = tmpEnd;
            }
        }
        return maxArea;
    }

    public int getArea(int[] height, int start, int end) {
        int startHeight = height[start];
        int endHeight = height[end];
        
        int minHeight = Math.min(startHeight, endHeight);
        int length = end - start;

        return minHeight * length;
    }
}

时间复杂度 O(n),n 为 height 数组的长度。

合并移动 index 的代码后,代码如下所示:

class Solution {
    public int maxArea(int[] height) {
        int length = height.length;
        int maxArea = 0;

        int start = 0;
        int end = length - 1;
        while (start < end) {
            int area = getArea(height, start, end);
            if (area > maxArea) {
                maxArea = area;
            }

            // 移动 height 值小的
            boolean moveStart = height[start] < height[end];
            if (moveStart) {
                // 移动 start
                // 移动到下一个 height 比当前大的 start
                start = getNextIndex(height, start, 1);
            } else {
                // 移动 end
                // 移动到下一个 height 比当前大的 end
                end = getNextIndex(height, end, -1);
            }
        }
        return maxArea;
    }

    public int getNextIndex(int[] heigth, int index, int delta) {
        int nextIndex = index;
        while (true) {
            // delta = 1 表示 start 向后移动
            // delta = -1 表示 end 向前移动
            nextIndex += delta;

            // 如果超出数组范围
            if (nextIndex < 0 || nextIndex >= heigth.length) {
                break;
            }

            // 如果 nextIndex 的 height 大于 index 的 height
            if (heigth[nextIndex] > heigth[index]) {
                break;
            }
            
        }
        return nextIndex;
    }

    public int getArea(int[] height, int start, int end) {
        int startHeight = height[start];
        int endHeight = height[end];
        
        int minHeight = Math.min(startHeight, endHeight);
        int length = end - start;

        return minHeight * length;
    }
}

时间复杂度 O(n),n 为 height 数组的长度。

相关文章

  • 0011. 盛最多水的容器

    题目地址 https://leetcode-cn.com/problems/container-with-most...

  • 盛最多水的容器

    给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直...

  • 盛最多水的容器

    盛最多水的容器 给定n个非负整数a1,a2,...,an,每个数代表坐标中的一个点(i,ai) 。画n条垂直线,使...

  • 盛最多水的容器

    题目来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/cont...

  • 盛最多水的容器

    题目描述 思路 题解代码

  • 盛最多水的容器

    盛最多水的容器 难度中等1826 收藏 分享 切换为英文 关注 反馈 给你 n 个非负整数 a1,a2,...,a...

  • 盛最多水的容器

    题目描述:  给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内...

  • 盛最多水的容器

    给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直...

  • 盛最多水的容器

    题目 https://leetcode-cn.com/problems/container-with-most-w...

  • 盛最多水的容器

    题目: 题目的理解: 计算两个数之间的面积,获取到最大的面积。 时间复杂度为O(n!), 当数量越大计算时间越长,...

网友评论

      本文标题:0011. 盛最多水的容器

      本文链接:https://www.haomeiwen.com/subject/cyfrbltx.html