目录
题目链接:
TT11. 盛最多水的容器 - 力扣(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。
分析
容积 = 长X宽 = 底 X高 = 间距 X最小的高度
如果使得盛水最多,
- 高要足够大,但是根据木桶原理的话,我们选择的高,应该是容器两边中更小的一边,才能保证水不会溢出。即使 6 号的高度是最高,我们选择 1 和 6 的话,计算出来的体积是 5 x 8 = 40 ,是小于 49 的,所以也不能选
- 还要考虑宽
暴力解法(会超时)
把所有情况全部遍历一遍。
利用两层循环,外层固定一个数组,内层一次往后找数组,当有更大的出现,就记录这个更大体积和两数组的位置。
//找比较小的
int getMin(int a, int b)
{
if (a < b)
return a;
else
return b;
}
//暴力解法
int maxArea1(int* height, int heightSize) {
int maxArea = 0;
for (int i = 0; i < heightSize; i++)
{
//面积 = min(a,b) * (b-a)
for (int j = i + 1; j < heightSize; j++)
{
int min = getMin(height[i], height[j]);
int tmp = min * (j - i);
if (tmp > maxArea)
maxArea = tmp;
}
}
return maxArea;
}
对撞双指针
初始化 left 和 right ,在数组头部、尾部
int left = 0, right = heightSize -1;
int maxArea = 0;
那怎么确定怎么移动letf和right呢?
left, right 在两端,移动间距只能变小。
因为移动间距减小了,那么代表容积=间距 X最小的高度,想要容积再大,只能移动高度,来减少面积的减少程度。选择高度更大的木板,可以尽量避免容积的减少。
int getMin(int a, int b)
{
if (a < b)
return a;
else
return b;
}
int maxArea(int* height, int heightSize) {
//定义双指针,指向数组头尾
int left = 0, right = heightSize -1;
int maxArea = 0;
while (left < right)
{
//h 高 wide宽
int h = getMin(height[left], height[right]);
int wide = right - left;
//临时面积
int area = h * wide;
//更新maxArea
if (area > maxArea)
maxArea = area;
//选取更高的木板
//一旦有一个木板更短,就移动这个木板
if (height[left] < height[right])
left++;
else
right--;
}
return maxArea;
}