题目
小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。
小Q从第一栋一直走到了最后一栋,小Q从来都没有见到这么多的楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)
输入描述:
输入第一行将包含一个数字n,代表楼的栋数,接下来的一行将包含n个数字wi(1<=i<=n),代表每一栋楼的高度。
1<=n<=100000;
1<=wi<=100000;
输出描述:
输出一行,包含空格分割的n个数字vi,分别代表小Q在第i栋楼时能看到的楼的数量。
示例1
输入
6
5 3 8 3 2 5
输出
3 3 5 4 4 4
说明
当小Q处于位置3时,他可以向前看到位置2,1处的楼,向后看到位置4,6处的楼,加上第3栋楼,共可看到5栋楼。当小Q处于位置4时,他可以向前看到位置3处的楼,向后看到位置5,6处的楼,加上第4栋楼,共可看到4栋楼。
链接:https://www.nowcoder.com/questionTerminal/35fac8d69f314e958a150c141894ef6a
来源:牛客网
解题思路
这道题就是昨天说的两个小时只写了两道题,其中一道只通过了一半测试用例的那道。
这里也附上只通过了一半的解法,没有特别要说明的,就是O(N*N)暴力破解,每查找一个位置都要遍历一遍数组,这大概就是会超时的原因。
其中的细节大概就是按情境将数组分成两部分处理,并由此写了两个函数,一个叫向前看(forward),另外一个叫向后看(backward),两个函数的处理内容是一样的。
也就是用temp维护一个临时最大值,如果后续遍历中遇到比temp更大的就更新temp,并将结果++。(这么一想这题果然是单调栈的典型应用呀,只是没有整理过单调栈的用法所以想不到)
然后就是单调栈的解法,解完所有的位置只需要遍历两次数组。
- 思路也是分成两步,第一步是向前看能看到多少楼,第二步是向后看能看到多少楼,最后加上自己就是所有能看到的楼。
- 向前(左)能看到多少楼,也就是遍历到自己时前面有几个单调递减数,所以是正着遍历。
- 向后(右)能看到多少楼,也就是遍历到自己时后面有多少单调递增数,正向遍历的时候没办法知道自己后面的情况,所以就用反向遍历,因为反向了,所以维护的栈也相应变成单调递减了。
代码(C++)
暴力版(只能通过一半测试用例)
#include<iostream>
#include<vector>
using namespace std;
int forward(vector<int>& wi,int i){
int res=0;
int temp=0;
if(i==0) return 0;
else{
for(int cnt=i-1;cnt>=0;--cnt){
if(wi[cnt]>temp){
res++;
temp=wi[cnt];
}
}
}
return res;
}
int backward(vector<int>& wi,int i){
int res=0;
int temp=0;
if(i==wi.size()) return 0;
else{
for(int cnt=i+1;cnt<wi.size();++cnt){
if(wi[cnt]>temp){
res++;
temp=wi[cnt];
}
}
}
return res;
}
int main(){
vector<int> wi;
int n=0;
int temp=0;
cin>>n;
for(int i=0;i<n;++i){
cin>>temp;
wi.push_back(temp);
}
vector<int> ans;
for(int i=0;i<wi.size();++i){
int v=forward(wi,i)+backward(wi,i);
ans.push_back(v+1);
}
for(int i=0;i<ans.size();++i){
cout<<ans[i]<<' ';
}
cout<<endl;
return 0;
}
单调栈
#include<vector>
#include<iostream>
#include<stack>
using namespace std;
int main(){
int n=0;
cin>>n;
vector<int> vec(n);
for(int i=0;i<n;++i){
cin>>vec[i];
}
stack<int> forward;
stack<int> backward;
vector<int> f_ans(n);
vector<int> b_ans(n);
for(int i=0;i<n;++i){
f_ans[i]=forward.size();
while(!forward.empty()&&vec[i]>=forward.top()) forward.pop();
forward.push(vec[i]);
}
for(int i=n-1;i>=0;--i){
b_ans[i]=backward.size();
while(!backward.empty()&&vec[i]>=backward.top()) backward.pop();
backward.push(vec[i]);
}
for(int i=0;i<n;++i){
cout<<f_ans[i]+b_ans[i]+1<<" ";
}
return 0;
}