大意:给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。
一、单调栈解法
使用单调递减的单调栈,按照每层可以接的水做累加。
假设 : 4 3 2 0 1 5
下标 : 0 1 2 3 4 5
那么按照单调栈,首先入栈4,3,2,0。
下一个值为1,1>0,0出栈,2>1
则2 0 1可以接水,高为min(2-0,1-0),宽为1,接水量为1,此时1入。
下一个值为5,5>1,1出栈,栈顶值为2
则2 1 5 可以接水,高为min(5-1,2-1),宽为2,接水量为2,此时因为2<5,则2出栈,继续计算,栈顶值为3,3 2 5又可以接水,以此类推直到栈顶元素大于5或为空
class Solution {
public:
int trap(vector<int>& height) {
stack<int > s;
int water = 0;
for (int i = 0; i < height.size(); i++)
{
while (!s.empty() && height[i] > height[s.top()])
{
int num = s.top();
s.pop();
while (!s.empty() && height[num] == height[s.top()])
s.pop();
if (!s.empty())
{
int wid = i - s.top() - 1;
//宽度
int he = min(height[i] - height[num], height[s.top()] - height[num]);
//高度
water += wid * he;
}
}
s.push(i);
}
return water;
}
};
二、双指针解法
核心思想:左右两个柱子中间能蓄水,决定蓄多少水取决于短的那根柱子。
设置 left,right 双指针,指向直方图首部和尾部,高度设置为leftmax,rightmax。
当leftmax<rightmaxm,则左边的柱子低于右边的柱子,则一个索引(index)下的蓄水量等于 , leftmax - height[index] 。反之左边同理
class Solution {
public:
int trap(vector<int>& height) {
if(height.size()<3) return 0;
int left=0,right=height.size()-1;
int leftmax=height[left],rightmax=height[right];
int water = 0;
while(left<right)
{
if(leftmax<rightmax)
{
water+=leftmax-height[left];
left++;//更新值
leftmax=max(leftmax,height[left]);
}
else
{
water+=rightmax-height[right];
right--;
rightmax=max(rightmax,height[right]);
}
}
return water;
}
};