题解 | #愤怒的小鸟#
愤怒的小鸟
https://www.nowcoder.com/practice/597c32f0b3cf43beb1d01e7ddd87cc32
- 方法:单调栈
- 思路:
- 首先找到每个点前面不能到达该点的节点数量:从前向后遍历,记录一个num表示前面所有节点中不能到达当前节点的数目,并维护一个单调递减的栈S。对于第i个节点,如果栈不为空且栈顶元素小于h[i],则一直弹出栈顶元素,并每次把num++,因为这些元素都不能到达当前节点。然后加入当前节点到栈顶,并更新当前节点的ans:ans[i]+=num。
- 其次找到每个点后面不能到达该点的节点数量:从后往前遍历,其余同上。
- 注意:单调栈的思想,大多是不单调的节点对后面的节点「没有影响」/「等于对当前节点的影响」。比如这道题中,如果前面某些点不能到达当前节点,那么他们就一定不能达到该节点后面的点,故这些点对后面的节点「等于对当前节点的影响」
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+10;
int n;
int h[MAXN];
int ans[MAXN];
stack<int>s;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&h[i]);
int num = 0;
for(int i=1;i<=n;++i){ //正向,找到每个节点前面不能到达当前节点数目
while(!s.empty() && s.top()<h[i]){
s.pop();
num++;
}
s.push(h[i]);
ans[i]+=num;
}
num = 0;
while(!s.empty())s.pop();
for(int i=n;i>=1;--i){ //逆向,找到每个节点后面不能到达当前节点数目
while(!s.empty() && s.top()<h[i]){
s.pop();
num++;
}
s.push(h[i]);
ans[i]+=num;
}
for(int i=1;i<=n;++i){
printf("%d",ans[i]);
i==n?printf("\n"):printf(" ");
}
}
// 64 位输出请用 printf("%lld")
查看16道真题和解析