给定一个长度为
n的整数数组height。有n条垂线,第i条线的两个端点是(i, 0)和(i, height[i])。找出其中的两条线,使得它们与
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
题解1 暴力解法
思路
题目要求我们求解容器的最大值,可以把 height[i] 看作一块木板,其实求的是面积的最大值。而两块木板的面积的最大值等于木板之间的间距 j - i * min(height[i], height[j]),因为水会从矮的那边流出去,所以要取最小值。
最简单的解法就是两层循环,第一层先确定 i 第二层从 i + 1 开始确定 j,然后求他们的面积。
而我们如何保证取到的是面积最大呢?在遍历的时候比较答案缓存下来。
一定要是两块最高的木板才是最大值吗?不一定,因为面积还受到间距的影响。
代码
function maxArea(height: number[]): number {
const len: number = height.length;
let result: number = 0;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
const area = (j - i) * Math.min(height[i], height[j]);
result = Math.max(result, area);
}
}
return result;
};
时空复杂度分析
时间复杂度:两层循环铁 O(n^2)。在leetcode上会超时
空间复杂度:没有额外缓存 O(1)
题解2 相向双指针
思路
我们思考一下暴力解法,内层循环会依次遍历一遍剩余数值,而如果最右侧的没有木板为 0,那么每次遍历它时都是空,即使是最高的木板和它构成容器都是徒劳,所以可以优化这里的重复计算。
所以可以用两个指针来相向遍历(两个指针从数组的两端开始,向中间移动) height 数组,比较两个木板的高度,每次移动较矮的指针。
代码
function maxArea(height: number[]): number {
const len: number = height.length;
let result: number = 0;
for (let i = 0, j = len - 1; i < j;) {
const area: number = (j - i) * Math.min(height[i], height[j]);
result = Math.max(result, area);
if (height[i] > height[j]) {
j--;
} else {
i++;
}
}
return result;
};
时空复杂度分析
时间复杂度:一次遍历 O(n)
空间复杂度:没有额外存储,O(1)