(刷题笔记) 牛客网 腾讯2020校园招聘-后台 2.逛街

这篇博客详细介绍了如何解决牛客网上的一道面试题,题目要求计算小Q在每栋楼的位置能看到多少栋楼。博主首先提供了O(N^2)的暴力解法,然后讲解了利用单调栈实现的O(N)解决方案,包括向前看和向后看两个步骤。代码示例中包含了暴力解法和单调栈解法。
摘要由CSDN通过智能技术生成

题目

小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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值