一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
11. 盛最多水的容器
题目描述
给定一个长度为 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
提示
n == height.length2 <= n <= 1050 <= height[i] <= 104
题解
本题很简单,就是通过输入的数组来计算最大的盛水容量,我们都知道,如果有两条垂线,那么能够盛水的高度肯定是以最短的那根线为准的,容量的计算方法就是两条垂线中最短的那条的高度 * 两条垂线之间的距离。
方法一
既然要计算最大值,那么最简单粗暴的方法就是直接使用循环,计算数组中每一个元素都和它后面的元素组成的容器大小,然后通过遍历找到最大值。
代码如下:
public int maxArea(int[] height) {
int res = 0;
for (int i = 0; i < height.length; i++) {
for (int j = i + 1; j < height.length; j++) {
res = Math.max(res, Math.min(height[i], height[j]) * (j - i));
}
}
return res;
}
代码解析
通过Math.min计算两条垂线中较短的的高度乘以 j - i 得到的两条垂线之间的距离就能得到容器的容量大小。
时间复杂度:O(N^2)。
由于需要对数组进行双重循环,所以最后的时间复杂度较高,并且该方法也无法通过所有的测试用例,提交会报出超出时间限制的错误。
方法二
既然使用方法一的暴力方式无法解决问题,那么就需要找到另外一种方式,既然使用双重循环不行,那么还有一种方法就是使用两个指针,分别指向数组的最前面和最后面,然后不断的移动左指针和右指针完成对数组的遍历查找最大值,但是在指针移动的过程中不可能同时移动两个指针,所以就需要找到一个判断条件来判断到底是移动左指针还是右指针,这个条件就是通过比较两个指针指向的位置的元素的大小,哪个指针的元素更小则移动哪个指针,更大的那个元素的指针不动。
代码如下:
public int maxArea(int[] height) {
int res = 0;
int i = 0;
int j = height.length - 1;
while (i < j) {
res = Math.max(res, Math.min(height[i], height[j]) * (j - i));
if (height[i] < height[j]) {
i++;
} else {
j--;
}
}
return res;
}
代码解析
时间复杂度:O(N)
通过该方法时间复杂度大大缩减,也可通过所有测试用例,假设盛水容量的公式为 w * h,使用双指针时,w 是不断递减的,在 w 递减的过程中通过改变 h 来找出最大的容量。