当青训营遇上码上掘金
主题4 攒青豆
第一眼看到这个题目,我就立马想到了以前在力扣上面刷到的一道题目,接雨水:
只不过力扣是雨水,这里是青豆
还是个困难的tag
前置知识
单调栈:
找出每个数字左边第一个小于自己的数字,没有的话返回-1
题目中会有两个性质:
1.如果height[i]>height[j] 并且 i<j 的话,height[i]肯定不会是正确答案
2.如果height[i]<height[j] 并且i<j的话,此次遍历的值可能是height[i]和height[j]中间或者两边,三种情况
其实先可以理解成,每遍历一个元素的时候,就从栈里找到最小的,然后将元素添加到栈顶...
有了上面的两个性质就可以这么做:
- 开辟一个栈
- 从栈顶开始遍历,直到把所有大于等于此次的遍历的数字的时候停止
- 如果栈空了,返回-1,不空的话返回栈顶
- 将此次遍历的值添加到栈顶
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
scanf("%d", &x);
while (tt && stk[tt] >= x)
tt -- ;
if (!tt) printf("-1 ");
else printf("%d ", stk[tt]);
stk[ ++ tt] = x;
}
return 0;
}
本题思路
举个例子:
1.首先前三个柱子入栈,不能形成凹槽,不能存青豆
2.第四根柱子就可以存青豆了,需要加上可以存储的部分
这么加:(栈顶元素加上上一个元素的高度差)
第二步结束之后其实栈里只有两根柱子:(单调栈初具雏形)
3.再加一根,形不成凹槽
4.下一根,需要加上一个凹槽
5.下一步加上这个
6.最后一步
7.我们最后可以来个最高的
此时栈中元素:(绿色的)
加上面积:
确实很难想!
代码:
class Solution {
public:
int trap(vector<int>& height) {
stack<int> stk;
int res = 0;
for (int i = 0; i < height.size(); i ++ ) {
// 这里有个巧妙的地方,就是当last为0的时候,第一次res+的是0,因为(i - stk.top() - 1)肯定是0,所以last的初始值取多少都行
int last = 0;
while (stk.size() && height[stk.top()] <= height[i]) {
res += (height[stk.top()] - last) * (i - stk.top() - 1);
last = height[stk.top()];
stk.pop();
}
if (stk.size()) res += (i - stk.top() - 1) * (height[i] - last);
stk.push(i);
}
return res;
}
};