• 腾讯2020校园招聘-后台&综合-第一次笔试 题解


    对数据结构和算法感兴趣的可以关注一下https://github.com/MCQ1999/Datastructure_Algorithm_Solutions,分享算法题的解题思路和代码~

    1.压缩算法(栈模拟)

    题意

    链接:https://www.nowcoder.com/questionTerminal/c27561e5b7e0441493adb9a54071888d
    来源:牛客网

    小Q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小Q发明了一种压缩算法对字符串中重复的部分进行了压缩,对于字符串中连续的m个相同字符串S将会压缩为m|S,例如字符串ABCABCABC将会被压缩为[3|ABC],现在小Q的同学收到了小Q发送过来的字符串,你能帮助他进行解压缩么?

    输入描述:

    输入第一行包含一个字符串s,代表压缩后的字符串。
    S的长度<=1000;
    S仅包含大写字母、[、]、|;
    解压后的字符串长度不超过100000;
    压缩递归层数不超过10层;

    输出描述:

    输出一个字符串,代表解压后的字符串。

    示例1
    输入

    HG[3|B[2|CA]]F

    输出

    HGBCACABCACABCACAF

    说明

    HG[3|B[2|CA]]F−>HG[3|BCACA]F−>HGBCACABCACABCACAF

    思路

    栈模拟。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
        stack<char> st;
        string s;
        cin>>s;
        int n=s.length();
        for(int i=0;i<n;i++){
            if(s[i]!=']'){
                st.push(s[i]);
            }else {
                string tmp="";
                while(st.top()!='|'){
                    tmp+=st.top();
                    st.pop();
                }
                reverse(tmp.begin(),tmp.end());
                string num="";
                st.pop();
                while(st.top()!='['){
                    num+=st.top();
                    st.pop();
                }
                st.pop();
                reverse(num.begin(),num.end());
                int x=stoi(num);
                string t="";
                while(x--){
                    for(char c:tmp){
                        st.push(c);
                    }
                }
            }
        }
        string ans;
        while(!st.empty()){
            ans+=st.top();
            st.pop();
        }
        reverse(ans.begin(),ans.end());
        cout<<ans<<endl;
        return 0;
    }
    

    2.逛街 (单调栈)

    题意

    链接:https://www.nowcoder.com/questionTerminal/35fac8d69f314e958a150c141894ef6a
    来源:牛客网

    小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栋楼。

    思路

    单调栈。
    维护从栈底到栈顶递减的栈,这么做的意义是正着遍历可以求出每个点往左边能看到的个数,倒着遍历求出每个点往右能看到的个数。比如正着遍历,因为栈里面元素是单减的,那么每个点往左看,栈里面都是大于这个点的,所以每次栈的大小就是对应的个数。最后再加上1就是答案了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int a[N],b[N];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        stack<int> st;
        for(int i=1;i<=n;i++){
            b[i]+=st.size();
            while(!st.empty()&&a[i]>=st.top()){
                st.pop();
            }
            st.push(a[i]);
        }
        while(!st.empty()) st.pop();
        for(int i=n;i>=1;i--){
            b[i]+=st.size();
            while(!st.empty()&&a[i]>=st.top()){
                st.pop();
            }
            st.push(a[i]);
        }
        for(int i=1;i<=n;i++){
            printf("%d ",b[i]+1);
        }
        puts("");
        return 0;
    }
    

    3.逆序对

    题意

    链接:https://www.nowcoder.com/questionTerminal/8fe007e54fc04b5e82089aaa71ba3553
    来源:牛客网

    作为程序员的小Q,他的数列和其他人的不太一样,他有2n2^n2n个数。
    老板问了小Q一共 m次,每次给出一个整数qi(1<=i<=m)q_i (1 <= i <= m)qi​(1<=i<=m), 要求小Q把这些数每2qi2^{q_i}2qi​分为一组,然后把每组进行翻转,小Q想知道每次操作后整个序列中的逆序对个数是多少呢?

    例如:
    对于序列1 3 4 2,逆序对有(4, 2),(3, 2),总数量为2。
    翻转之后为2 4 3 1,逆序对有(2, 1),(4, 3), (4, 1), (3, 1),总数量为4。

    输入描述:

    第一行一个数n(0≤n≤20)n(0 leq n leq 20)n(0≤n≤20)
    第二行2n2^n2n个数,表示初始的序列(1≤初始序列≤1091 leq 初始序列 leq 10^91≤初始序列≤109)
    第三行一个数m(1≤m≤106)m(1 leq m leq 10^6)m(1≤m≤106)
    第四行m个数表示qi(0≤qi≤n)q_i(0 leq q_i leq n)qi​(0≤qi​≤n)

    输出描述:

    m行每行一个数表示答案。

    示例1
    输入

    2
    2 1 4 3
    4
    1 2 0 2

    输出

    0
    6
    6
    0

    说明

    初始序列2 1 4 3
    2q1=22^{q_1} = 22q1​=2 ->
    第一次:1 2 3 4 -> 逆序对数为0
    2q2=42^{q_2} = 42q2​=4 ->
    第二次:4 3 2 1 -> 逆序对数为6
    2q3=12^{q_3} = 12q3​=1 ->
    第三次:4 3 2 1 -> 逆序对数为6
    2q4=42^{q_4} = 42q4​=4 ->
    第四次:1 2 3 4 -> 逆序对数为0

    思路

    咕咕咕

    4.假期(动态规划)

    题意

    链接:https://www.nowcoder.com/questionTerminal/7cd9a140387e455a972e8fea0e74be2c
    来源:牛客网

    由于业绩优秀,公司给小Q放了 n 天的假,身为工作狂的小Q打算在在假期中工作、锻炼或者休息。他有个奇怪的习惯:不会连续两天工作或锻炼。只有当公司营业时,小Q才能去工作,只有当健身房营业时,小Q才能去健身,小Q一天只能干一件事。给出假期中公司,健身房的营业情况,求小Q最少需要休息几天。

    输入描述:

    第一行一个整数 n(1≤n≤100000)n(1leq nleq 100000)n(1≤n≤100000) 表示放假天数
    第二行 n 个数 每个数为0或1,第 i 个数表示公司在第 i 天是否营业
    第三行 n 个数 每个数为0或1,第 i 个数表示健身房在第 i 天是否营业
    (1为营业 0为不营业)

    输出描述:

    一个整数,表示小Q休息的最少天数

    示例1
    输入

    4
    1 1 0 0
    0 1 1 0

    输出

    2

    说明

    小Q可以在第一天工作,第二天或第三天健身,小Q最少休息2天

    思路

    dp(i,0)表示在到第i天工作所能休息的最少天数,dp(i,1)表示在到第i天健身所能休息的最少天数,dp(i,2)表示在到第i天休息所能休息的最少天数。
    那么
    如果第i天能工作,肯定是从第i-1天不工作转移过来
    如果第i天能健身,肯定是从第i-1天不健身转移过来
    第i天休息,则是从第i-1天三种状态转移过来,因为没有要求不能连续休息两天。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int a[N],b[N],dp[N][3];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&b[i]);
        }
        memset(dp,0x3f3f3f3f,sizeof(dp));
        if(a[1]){
            dp[1][0]=0;
        }
        if(b[1]){
            dp[1][1]=0;
        }
        dp[1][2]=1;
        for(int i=2;i<=n;i++){
            if(a[i]){
                dp[i][0]=min(dp[i-1][1],dp[i-1][2]);
            }
            if(b[i]){
                dp[i][1]=min(dp[i-1][0],dp[i-1][2]);
            }
            dp[i][2]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+1;
        }
        printf("%d
    ",min(dp[n][0],min(dp[n][1],dp[n][2])));
        return 0;
    }
    

    5.视野争夺 (贪心)

    题意

    链接:https://www.nowcoder.com/questionTerminal/61e1e66e39f348cdb6495de91ac36a41
    来源:牛客网

    小Q在进行一场竞技游戏,这场游戏的胜负关键就在于能否能争夺一条长度为L的河道,即可以看作是[0,L]的一条数轴。
    这款竞技游戏当中有n个可以提供视野的道具−真视守卫,第i个真视守卫能够覆盖区间[xi,yi]。现在小Q想知道至少用几个真视守卫就可以覆盖整段河道。

    输入描述:

    输入包括n+1行。

    第一行包括两个正整数n和L(1<=n<=105,1<=L<=109)

    接下来的n行,每行两个正整数xi,yi(0<=xi<=yi<=109),表示第i个真视守卫覆盖的区间。

    输出描述:

    一个整数,表示最少需要的真视守卫数量, 如果无解, 输出-1。

    示例1
    输入

    4 6
    3 6
    2 4
    0 2
    4 7

    输出

    3

    思路

    按左端点从小到大,右端点从大到小排序,每次看一个区间能里的点往右最大能延伸到哪(mx),下次更新上限(up)的时候就用这个mx。这个过程和leetcode跳跃游戏那题很像。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    struct node{
        int l,r;
        bool operator<(node b){
            if(l==b.l){
                return r>b.r;
            }
            return l<b.l;
        }
    }g[100005];
    int main(){
        int n,L;
        scanf("%d%d",&n,&L);
        for(int i=0;i<n;i++){
            scanf("%d%d",&g[i].l,&g[i].r);
        }
        sort(g,g+n);
        int up=g[0].r,mx=g[0].r,cnt=1;
        if(g[0].l>0) {
            printf("-1
    ");
            return 0;
        }
        for(int i=1;i<n;i++){
            if(g[i].l<=up){
                mx=max(g[i].r,mx);
                if(mx>=L){
                    printf("%d
    ",cnt+1);
                    return 0;
                }
            }else {
                cnt++;
                up=max(up,mx);
     
                i--;
            }
        }
        if(mx<L){
            printf("-1
    ");
            return 0;
        }
        printf("%d
    ",cnt);
        return 0;
    }
    

    总结

    腾讯的笔试题做起来还是有点难度的,考察点也比较全(贪心、dp、数据结构),题目也很有价值,值得反复做。

  • 相关阅读:
    fjnu2019第二次友谊赛 B题
    2019年FJNU低编赛 G题(dfs博弈)
    洛谷P2634 聪聪可可 (点分治)
    洛谷P3128 [USACO15DEC]最大流Max Flow (树上差分)
    Comet OJ
    Comet OJ
    Comet OJ
    Comet OJ
    Django models操作、中间件、缓存、信号、分页
    Ajax
  • 原文地址:https://www.cnblogs.com/mcq1999/p/12345500.html
Copyright © 2020-2023  润新知