腾讯2020年校招[2/5]
此博客用作本人进行校招试题及解法的记录,内容主要用于本人今后的阅读,故博客写法以便于本人后续阅读的方式为主。
试题
题目描述
小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。小Q从第一栋一直走到了最后一栋,小Q从来都没有见到这么多的楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)
输入描述
输入第一行将包含一个数字n,代表楼的栋数,接下来的一行将包含n个数字wi(1<=i<=n)
代表每一栋楼的高度。
1<=n<=100000;1<=wi<=100000;
输出描述
输出一行,包含空格分割的n个数字vi,分别代表小Q在第i栋楼时能看到的楼的数量。
输入例子
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栋楼。
解答
通过阅读题目,我们最容易想到的解法就是暴力遍历,其时间复杂度为O(n2)用这种方法肯定会超时,使用单调栈可以完成算法在时间上的优化,将时间复杂度降低到O(nlogn)。
首先先了解一下什么是单调栈。
单调栈中存放的数据应该是有序的,分为单调递增栈和单调递减栈
- 单调递增栈:数据出栈的序列为单调递增序列
- 单调递减栈:数据出栈的序列为单调递减序列
这里一定要注意所说的递增递减指的是出栈的顺序,而不是在栈中数据的顺序
例子
现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。
- 10入栈时,栈为空,直接入栈,栈内元素为10。
- 3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。
- 7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。
- 4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。
- 12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。
继续解答
通过上述方法我们就能设计出符合要求的算法。将每一个位置能看见的房屋看成左右两个部分,要求栈中数据从栈底到栈顶要递减,且左边的房屋要从左往右遍历,右边的房屋要从右往左遍历,且下一次遍历都是在上一次的结果上直接进行(左右遍历是独立的,需要两个栈,并用两个数组存储栈内所含元素的各数,这两个数分别标识向左看能看见的房屋数和向右看能看见的房屋数),这样一来就不用每一个元素都从头比较一遍。
代码
#include <stack>
#include <iostream>
using namespace std;
int main(){
int building[1000000];
int num, i;
cin>>num;
for(i = 0; i < num;i++){
cin>>building[i];
}
stack<int> right;//向右看能看见的楼高度
stack<int> left;//向左看能看见的楼高度
int R[1000000], L[100000];//左右分别可以看见的楼的数量
for(i = 0; i < num;i++){
R[i] = right.size();
if(i == 0)
right.push(building[0]);
else if (right.top() > building[i]){
right.push(building[i]);
}
else{
while(!right.empty() && right.top() <= building[i]){
right.pop();
}
right.push(building[i]);
}
}
for(i = num - 1; i >= 0;i--){
L[i] = left.size();
if(i == num - 1)
left.push(building[num - 1]);
else if (left.top() > building[i]){
left.push(building[i]);
}
else{
while(!left.empty() && left.top() <= building[i]){
left.pop();
}
left.push(building[i]);
}
}
for(i = 0;i < num; i++)
cout<<L[i] + R[i] + 1 <<" ";
}