11. 盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题
双指针
双指针包括头指针,尾指针,一起向中心遍历;
条件为
左右指针指向的边长大的一方不动,小的一方向内遍历,若求得的面积比已保存的最大面积大,则更新最大面积;
class Solution {
public:
int maxArea(vector<int>& height) {
int head=0;
int tail=height.size()-1;
int m=min(height[tail],height[head])*(tail-head);
while(head<tail)
{
if(height[head]>height[tail]) --tail;
else ++head;
int t=min(height[tail],height[head])*(tail-head);
if(m<t) m=t;
}
return m;
}
};
总结
利用双指针时,每次只移动一个指针,移动条件是比较两个指针指向数值的大小。
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
双指针方法
除了需要头尾指针遍历外,还需要额外的变量储存当前左边最高的墙和右边最高的墙;
比较头尾指针大小,小的移动;
比较移动后指针指向数值的大小和已保存的最大值大小,若更大,则更新最大值,若小,则在Sum总数里增加移动的指针已保存的最大值和当前值的差;
class Solution {
public:
int trap(vector<int>& height) {
int left=0;
int right=height.size()-1;
int maxleft=0;
int maxright=0;
int Sum=0;
while(left<right)
{
if(height[left]<height[right]){ //说明maxleft也小于right
if(height[left]>maxleft)
maxleft= height[left];
else //left高度小于左边的最大高度
Sum+=maxleft-height[left];
++left;
}
else {
if(height[right]>maxright)
maxright=height[right];
else
Sum+=maxright-height[right];
--right;
}
}
return Sum;
}
};
注意点
因为移动左指针的条件是左指针高度小于右指针;
故左指针的max高度一定也小于右指针,不然就会一直停在max上不动;
当移动的左指针更新了新的maxleft后,若maxleft此时大于右指针的数值,这时移动右指针;
所以当一个指针移动时,另一个指针必指向它当时的max高度,此时当前指针要加入的水量直接用当前移动指针的max高度减去当前移动指针的高度即可;
动态规划
计算每一列的高度,可由该列左右最高高度里低的那一个减去自身高度得到;
即 min(rightmax[i],leftmax[i])-height[i];
用动态规划求出每个点左右的最高高度,即可在N时间内完成;
class Solution {
public:
int trap(vector<int>& height) {
if(height.size()==0)
return 0;
vector<int> leftmax(height.size()); //存放i左边的最高墙
vector<int> rightmax(height.size()); //存放i右边的最高墙
leftmax[0]=height[0];
rightmax[height.size()-1]=height[height.size()-1];
for(int i=1;i<height.size();i++)
leftmax[i]=max(leftmax[i-1],height[i]);
for(int i=height.size()-2;i>=0;i--)
rightmax[i]=max(rightmax[i+1],height[i]);
//计算总面积
int Sum=0;
for(int i=0;i<height.size();i++)
Sum+=min(rightmax[i],leftmax[i])-height[i];
return Sum;
}
};