百度正式批笔经(研发A卷,算法题解+AK代码)
笔试:2022.09.13
岗位:c++研发工程师
时长:2小时(实际完成1小时)
在牛客上进行
经验教训:
一定要带好纸和笔!!!(全程无纸笔,只能痛苦乱答了)
单选题+多选题,八股知识
算法题
题目1
题面
判断一个长字符串,包含几个“baidu”型字符子串。”baidu”型字符串定义为,长度为5的字符串,任意两个字符不同,且第一第四位是辅音字母,另外三位是元音字母。字符串长度为20万。
思路
看清题意,暴力判断就行了
代码
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <cmath> using namespace std; string s; bool check(const char &ch) { if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') return true; return false; } int main() { cin >> s; int n = s.size(); int ans = 0; for (int i = 0; i < n - 4; ++i) { bool flag = 1; if (check(s[i]) || check(s[i+3]) || !check(s[i+1]) || !check(s[i+2]) || !check(s[i+4])) continue; for (int j = 0; j < 5; ++j) for (int k = j + 1; k < 5; ++k) if (s[i+j] == s[i+k]) flag = 0; ans += flag; } cout << ans <<endl; return 0; }
题目2
给q个字符串,每个字符串包含01。一个字符串能翻转任意次,每次翻转相邻两个数。求这q个字符串,能否变为全0或全1。字符串总长度20万。
思路
蛮有意思的题目,分享两个做法。
第一个做法:找规律
假设我们把所有相邻的1都变成0,其他1都是孤立的,可以全部交换到队列开头,那么只要判断奇偶,就知道是否能全部变成0。
做法很简单,只要对整个序列求一遍异或和即可。
(考场我只想到了这里,提交后只有10分)
但是这样可能有问题,比如010,它的最终答案是全1的,不能变成全0。
怎么办呢,把01交换,重新跑一遍。两次只要有一次是Yes,答案就是Yes。
第二个做法:动态规划
考虑到交换只能是相邻的,也就是我们当前是否交换只和上一个状态有关,很自然地想到用动态规划。
只有上一个状态,不好转移,还要考虑前面是变成了全0或者全1。
我设置了4个状态
f[i][0][0]表示最后一位为0,前面i-1位均为0,是否有解
f[i][0][1]表示最后一位为0,前面i-1位均为1,是否有解
f[i][1][0]表示最后一位为1,前面i-1位均为0,是否有解
f[i][1][1]表示最后一位为1,前面i-1位均为1,是否有解
每步的转移其实就两种情况,i翻转或者不翻转,所以有8个转移方程,具体看代码。
最终当f[n-1][0][0]为true,或者f[n-1][1][1]为true,即为Yes。
代码
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <cmath> using namespace std; string s; bool f[200005][2][2]; int main() { int q; cin >> q; while (q--) { cin >> s; int n = s.size(); if (s[0] == '0') { f[0][0][0] = f[0][0][1] = true; f[0][1][0] = f[0][1][1] = false; } else { f[0][0][0] = f[0][0][1] = false; f[0][1][0] = f[0][1][1] = true; } for (int i = 1; i < n; ++i) { f[i][0][0] = f[i][0][1] = f[i][1][0] = f[i][1][1] = false; if (s[i] == '0') { f[i][0][0] |= f[i-1][0][0]; f[i][0][1] |= f[i-1][1][1]; f[i][1][0] |= f[i-1][1][0]; f[i][1][1] |= f[i-1][0][1]; } else { f[i][0][0] |= f[i-1][1][0]; f[i][0][1] |= f[i-1][0][1]; f[i][1][0] |= f[i-1][0][0]; f[i][1][1] |= f[i-1][1][1]; } } if (f[n-1][0][0] || f[n-1][1][1]) cout << "Yes" << endl; else cout << "No" << endl; } return 0; }
题目3
N*M的字符矩阵,包含red三个字母。有三条路是不能走的,”r->d”,”e->r”,”d->e”。求左上角到右下角的最段路。
思路
带障碍的,边权为1的最短路。
经典BFS(宽度优先搜索问题)
代码
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <cmath> using namespace std; int n, m; char A[505][505]; int Q[2500005][2], dis[505][505]; const int fx[4] = {0, 1, -1, 0}; const int fy[4] = {1, 0, 0, -1}; int main() { cin >> n >> m; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { scanf(" %c", &A[i][j]); dis[i][j] = 1e9; } int l = 0, r = 1; Q[0][0] = 0, Q[0][1] = 0; dis[0][0] = 0; while (l < r) { for (int t = 0; t < 4; ++t) { int ux = Q[l][0]; int uy = Q[l][1]; int tx = ux + fx[t]; int ty = uy + fy[t]; if (tx < 0 || tx >= n || ty < 0 || ty >= m) continue; if ((A[ux][uy] == 'r' && A[tx][ty] == 'd') || (A[ux][uy] == 'e' && A[tx][ty] == 'r') || (A[ux][uy] == 'd' && A[tx][ty] == 'e')) continue; if (dis[tx][ty] > dis[ux][uy] + 1) { dis[tx][ty] = dis[ux][uy] + 1; Q[r][0] = tx; Q[r][1] = ty; r++; } } l++; } if (dis[n-1][m-1] == 1e9) cout << -1; else cout << dis[n-1][m-1]; return 0; }
八股完成总时长:20分钟;
算法题完成总时长:40分钟;
得分100+100+100=300。
算法不难,八股比较难。
希望百度还有HC给正式批的笔试同学哈哈~