2021.3.27 米哈游笔试

不得不说,原本以为没有很难,结果没想到比字节的题还难,不愧是国际大厂 。直接凉凉,心态大蹦。
DP场?前三题全是DP,第四题字符串建树检索,第五题高难图论

一、 给一个纯数字字符串 S S S,让你求必须按"1807"的顺序的最长子序列。( ∣ S ∣ ≤ 1 0 5 |S| \le 10^5 S105
比如 “1800077000007”
他可以取子序列 “18000777”(取了中间两个7,则后面的7中间的0就不能取,因为必须要按1807的顺序,但是可以取多个1,8,0,7)
也可以取 “18000000007”
当然,最长的是 “18000000007”,所以答案为11。

思路:
DP4次:
dp1[i]表示前i个字符串最长的"1"的数量
dp2[i]表示前i个字符串最长的"18"的数量
dp3[i]表示前i个字符串最长的"180"的数量
dp4[i]表示前i个字符串最长的"1807"的数量
dp2[i]前必须要出现1,才能dp出最长18的,否则只有8则不行
dp3[i]前必须要出现18,才能dp出最长180的,否则只有0则不行
dp4[i]前必须要出现180,才能dp出最长1807的,否则只有7则不行
所以这个时候,每次DP都需要做一个标记:
vis1[i]=1表示前i个字符串出现过"1"
vis2[i]=1表示前i个字符串出现过"18"
vis3[i]=1表示前i个字符串出现过"180"
循环四次分别按顺序计算出四个dp数组,然后答案为dp4[k.size()-1];
dp公式:

// dp1:
if(k[i]=='1') {
	dp[0][i]=dp[0][i-1]+1;
    vis[0][i]=1; //第i位前出现过1
}
else {
    dp[0][i]=dp[0][i-1];
    vis[0][i]=vis[0][i-1];
}

//dp2:
if(k[i]=='8'&&vis[0][i-1]) { //如果前面一位出现过1
	dp[1][i]=max(dp[1][i-1]+1,dp[0][i-1]+1); //max(最后一个是8,或者最后多个8)
    vis[1][i]=1; //第i位前出现过18
}
else {
    dp[1][i]=dp[1][i-1];
    vis[1][i]=vis[1][i-1];
}

//dp3:
if(k[i]=='0'&&vis[1][i-1]) { //如果前面一位出现过18
	dp[2][i]=max(dp[2][i-1]+1,dp[1][i-1]+1); //max(最后一个是0,或者最后多个0)
    vis[2][i]=1; //第i位前出现过180
}
else {
    dp[2][i]=dp[2][i-1];
    vis[2][i]=vis[2][i-1];
}

//dp4:
if(k[i]=='7'&&vis[2][i-1]) { //如果前面一位出现过180
	dp[3][i]=max(dp[3][i-1]+1,dp[2][i-1]+1); //max(最后一个是7,或者最后多个7)
}
else {
    dp[3][i]=dp[3][i-1];
    vis[3][i]=vis[3][i-1];
}

当时做的时候没有考虑要判断前面是否出现过必须出现1,18,180,就直接dp。。当时感觉思路非常正确,样例都过完了,结束之后问了各位金牌爷他们也没看出来问题。但是就是没有100%,当时心态大蹦

现在突然想到需要加个标记…现在也心态大蹦…

参考代码:

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define MP make_pair
using namespace std;

const int maxn=1e5+10;

int dp[4][maxn];
int vis[3][maxn]; //vis[i][j] 表示前j位出现过{1,8,0}

//1800077000007

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    string k;
    cin>>k;
    if(k[0]=='1') {
        dp[0][0]=1;
        vis[0][0]=1;
    }
    for(int i=1;i<k.length();i++) {
        if(k[i]=='1') {
            dp[0][i]=dp[0][i-1]+1;
            vis[0][i]=1; //第i位前出现过1
        }
        else {
            dp[0][i]=dp[0][i-1];
            vis[0][i]=vis[0][i-1];
        }
    }

    for(int i=1;i<k.length();i++) {
        if(k[i]=='8'&&vis[0][i-1]) { //如果前面一位出现过1
            dp[1][i]=max(dp[1][i-1]+1,dp[0][i-1]+1); //max(最后一个是8,或者最后多个8)
            vis[1][i]=1; //第i位前出现过18
        }
        else {
            dp[1][i]=dp[1][i-1];
            vis[1][i]=vis[1][i-1];
        }
    }

    for(int i=2;i<k.length();i++) {
        if(k[i]=='0'&&vis[1][i-1]) { //如果前面一位出现过18
            dp[2][i]=max(dp[2][i-1]+1,dp[1][i-1]+1); //max(最后一个是0,或者最后多个0)
            vis[2][i]=1; //第i位前出现过180
        }
        else {
            dp[2][i]=dp[2][i-1];
            vis[2][i]=vis[2][i-1];
        }
    }

    for(int i=3;i<k.length();i++) {
        if(k[i]=='7'&&vis[2][i-1]) { //如果前面一位出现过180
            dp[3][i]=max(dp[3][i-1]+1,dp[2][i-1]+1); //max(最后一个是7,或者最后多个7)
        }
        else {
            dp[3][i]=dp[3][i-1];
            vis[3][i]=vis[3][i-1];
        }
    }

    if(k.length()<4) cout<<0<<endl;
    else cout<<dp[3][k.length()-1]<<endl;
    return 0;
}

二、 n n n 个项目,一开始的时间为 0,完成每个项目所需时间为 1,每个项目 i i i 有一个截止时间 t i t_i ti,如果在这个时间之前完成这个项目,则可以获得积分 w i w_i wi ,否则扣除积分 w i w_i wi 。 ( n ≤ 1 0 5 n \le 10^5 n105

思路:
DP

三、 给一个区间 [ L , R ] [L,R] [L,R] ,问在这个区间内的所有数字里,奇数位的和与偶数位的和相等的数有多少个。( 1 ≤ L ≤ R ≤ 1 0 9 1 \le L \le R \le 10^9 1LR109
比如 242 :奇数位的和为 2+2=4 ,偶数位的和为 4,所以满足条件。

思路:
数位DP

四、
给一个字符串 S 表示一颗二叉树,他的格式如下:
" 10 ( 5 ( 4 , 3 ) , 6 ( , 2 ) ) " "10(5(4,3),6(,2))" "10(5(4,3),6(,2))"
10 ( 5 , 6 ) 10(5,6) 10(5,6) 表示节点10的左子树为5,右子树为6。
6 ( , 2 ) 6(,2) 6(,2) 表示节点6的左子树为空,右子树为2。
如果节点右边没有括号,则表示这个节点为叶子节点。
让你输出这个字符串表示的树的中序遍历。( ∣ S ∣ ≤ 1 0 5 |S| \le 10^5 S105

思路:
重点在于解析这个字符串。
对这个字符串进行dfs,

node* dfs(string k,int l,int r) {}

表示返回从字符串从 l − > r l->r l>r 的子节点
找到这个节点之后的第一个括号,然后再对这个括号深度的逗号左边进行dfs,对这个括号深度的逗号右边进行dfs,分别绑定到这个节点的左子树和右子树上。
l > r l>r l>r 的时候则返回一个空节点。
l = = r l==r l==r 的时候则返回当前的叶子节点。
对于绑定完左右子树的节点,则返回当前节点。
中序遍历就不用多说,按"左根右"的顺序dfs即可。
具体可以看参考代码。

AC参考代码:

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define MP make_pair
using namespace std;

const int maxn=1e7+10;

int ans[maxn];

struct node {
    string val;
    node *lef;
    node *rig;
};

//解析字符串
node *dfs(string k,int l,int r) {
    if(l>r) return nullptr;
    if(l==r) {
        node *tmp=new node;
        tmp->val=k.substr(l,1);
        tmp->lef=nullptr;
        tmp->rig=nullptr;
        return tmp;
    }
    int nexl=0,nexr=0,mid=0;
    int deep=0;
    for(int i=l;i<r;i++) {
        if(k[i]=='(') {
            deep++;
            if(deep==1) {
                nexl=i;
            }
        } else if(k[i]==')'){
            deep--;
            if(deep==0) {
                nexr=i;
            }
        }
        if(k[i]==','&&deep==1) {
            mid=i;
            break;
        }
    }
    node *now=new node;
    now->val=k.substr(l,nexl-l);
    now->lef=dfs(k,nexl+1,mid-1);
    now->rig=dfs(k,mid+1,r-1);
    return now;
}

void middfs(node *root) {
    if(root==nullptr) return;
    middfs(root->lef);
    cout<<root->val<<" ";
    middfs(root->rig);
}

//10(5(4,3),6(,2))

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    string st;
    cin>>st;
    node *root=new node;
    root=dfs(st,0,st.size()-1);
    middfs(root);
    cout<<endl;
    return 0;
}

五、 有一个图,有 n n n 个节点,图中有两种边,输入 u , v u,v u,v表示每种边的数量,以下 u u u 行每行 a , b a,b a,b 表示 a 与 b a 与 b ab 连接第一种边,以下 v v v 行每行 c , d c,d c,d 表示 c 与 d c 与 d cd 连接第二种边。 ( 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105
输出每个节点能通过两种边都能到达的点的数量(包括自己)。

例如:

6 4 3
1 4
1 3
1 2
5 6
1 3
3 6
2 6

则建图如下:
在这里插入图片描述
1通过两种边都能到达的点有1,2,3
2通过两种边都能到达的点有1,2,3
3通过两种边都能到达的点有1,2,3
4通过两种边都能到达的点有4
5通过两种边都能到达的点有5
6通过两种边都能到达的点有6
所以输出

3 3 3 1 1 1

思路:
不会做,感觉是 CF difficulty 2400 以上的题

  • 7
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 米哈游是一家以游戏开发为主要业务的公司,Java后端笔试可能会涉及以下方面的内容: 1. Java基础知识:笔试中可能会涉及Java的基本语法、面向对象编程、集合框架等内容,考察应聘者对Java语言的熟悉程度。 2. 数据库:Java后端开发常常需要与数据库进行交互,因此笔试中可能会考察SQL语句的编写、数据库设计与优化等方面的知识。 3. Web开发:Java后端开发通常需要熟悉一些Web开发技术,如Servlet、JSP、Spring框架等。笔试中可能会出现相关的题目,考察应聘者对Web开发的了解程度。 4. 网络通信:Java后端开发常常需要进行网络通信,可能会使用TCP/IP协议、HTTP协议等。笔试中可能会出现与网络通信相关的题目,考察应聘者对网络通信知识的掌握。 5. 算法与数据结构:Java后端开发中,对算法与数据结构的理解与运用也非常重要。笔试中可能会出现一些与算法与数据结构相关的题目,考察应聘者的编程能力与解决问题的能力。 米哈游作为一家游戏开发公司,对Java后端开发人员的要求较高。参加该公司笔试需要对Java开发、数据库、Web开发、网络通信等方面的基础知识有一定的了解与掌握。同时,还需要有较强的编程能力和解决问题的能力。只有掌握了这些知识和能力,才能在米哈游的Java后端笔试中有所斩获。 ### 回答2: 米哈游java后端笔试米哈游公司的一项面试程序,用于选拔适合担任java后端开发职位的候选人。此笔试主要考察候选人在java后端开发方面的知识和技能。 在笔试中,候选人可能会遇到一些关于java编程语言和相关技术的问题。这些问题可能涉及到java的基本语法、面向对象编程、异常处理、多线程、IO操作等方面的内容。候选人需要能够熟练运用这些知识解决问题,并编写高质量的java后端代码。 此外,笔试可能还包括一些与数据库相关的问题,例如SQL查询语句的编写、数据库连接和事务处理等。候选人需要熟悉关系型数据库的基本概念和操作,以及常见的数据库管理系统如MySQL或Oracle等。 另外,米哈游java后端笔试也可能要求候选人解决一些算法和数据结构方面的问题。这些问题可能涉及到数组、链表、树、图等数据结构的使用以及常见的算法如搜索、排序和动态规划等。 总之,米哈游java后端笔试是一项通过考察候选人的java后端开发技能,来评估其适应米哈游公司java后端开发职位的能力和潜力的评估工具。候选人需要在笔试中展示他们在java编程语言、数据库和算法方面的扎实知识和解决问题的能力。 ### 回答3: 米哈游java后端笔试米哈游公司针对java后端开发岗位的面试笔试笔试内容主要考察应聘者在java开发方面的能力和经验。 笔试可能包括以下几个方面的内容: 1. Java基础知识:包括Java语法、面向对象编程、集合框架等基础知识。应聘者需要熟悉Java的常用类库和API,能够编写简单的Java程序。 2. 数据库和SQL:应聘者需要熟悉数据库的基本概念和常用操作,熟练使用SQL语言进行数据的查询和操作。可能需要编写一些简单的SQL语句。 3. Web开发:应聘者需要了解常用的Web开发技术,如Servlet、JSP、Spring、MyBatis等。可能需要编写一些简单的Web应用程序,实现基本的增删改查功能。 4. 多线程编程:应聘者需要理解多线程编程的基本概念和原理,能够使用Java提供的多线程相关API进行并发编程。 5. 性能优化和调优:应聘者需要了解如何进行性能优化和调优,能够使用一些常用的工具对程序进行性能分析和调试。 6. 设计模式:应聘者需要了解常用的设计模式,能够根据实际需求进行合理的设计和开发。 针对这些内容,应聘者可以提前进行充分准备,复习相关知识。同时,应该注重实践,多做一些相关的项目和练习题,提高自己的实际动手能力。 对于笔试中遇到的问题或难点,应聘者可以积极思考和分析,尽量给出自己的解决方案。如果不确定的地方可以标明,并在之后的面试环节中与面试官进行深入讨论。 最后,应聘者在笔试过程中要保持冷静和自信,展示出自己的优势和能力。希望以上回答能对你有所帮助。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值