第二个offer, 腾讯前端
字节跳动面试完,就接到了腾讯的面试邀请,前前后后大概10多天吧,终于拿到了腾讯的offer(不得不说腾讯效率真比字节跳动低,字节跳动,一晚上三面,然后2天后就给我发offer了)
腾讯一面(电话面试):
估计自己面完字节跳动,感觉有点飘,觉得字节跳动这么难都能面的上,腾讯应该就很简单。一面的面试官,先是要我自我介绍,我就说自己xxx大学,现在大三,成绩年级第二,平常利用自己的空余时间学习了前端等等,然后要我说了说自己在大学做的一下项目,反正一共说了四个,从用c++到java到前端,每一个项目都给他详细的说了一遍,然后就是问一些前端基础了,比如说一下html的标签,css的属性(腾讯是瞧不起我咋地(╬▔皿▔)凸,问我种问题,这随口一说就二三十个的),然后问了一些css布局的东西,问了浏览器事件机制,问了常见的状态码等等,其他题目记不太清了,记得他还跟我说我的前端水平在校招生中是比较高的。然后问了几道思维题,具体题目记不清了╥﹏╥...,然后还问了快速排序,这个说了算法思想,时空复杂度,怎么实现的等等。最后他说我一面没问题,说二面的话会考我基础的算法能力,数据结构等等,要我准备准备。
腾讯二面(视频面试):
记得好像一面完一天后就给我发二面的消息,二面的话就考了我四道算法题(虽然自己很久没刷算法题了,但是底子还是有的,大一的时候非常热衷于刷算法题,天天做题,可惜的就是大一的时候没有参加acm (ノへ ̄、))。
第一题:给定两个字符串s1,s2,s2中出现的字符从s1中删除
思路:当时面试官要我选择自己擅长的语言写,我选了JavaScript
function remove(s1, s2) {
for (let i = 0, len = s2.length; i < len; i ++ ) {
let r = new RegExp(s2[i], "g");
if (r.test(s1)) {
s1 = s1.replace(r, "")
}
}
return s1
}
当然自己当时脑子没转过弯来,没有想用c++咋做,用c++的话用个数组记就可以了
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
const int N = 129;
string remove(string s1, string s2) {
bool m[N];
memset(m, 0, sizeof(m));
string result;
for (int i = 0, len = s2.size(); i < len; i++) {
m[s2[i] - 'a'] = true;
}
for (int i = 0, len = s1.size(); i < len; i++) {
if (!m[s1[i] - 'a']) {
result.push_back(s1[i]);
}
}
return result;
}
int main() {
string s1 = "hahaacc", s2 = "bcabaccc";
cout<<remove(s1, s2)<<endl;
return 0;
}
第二题:判断一棵树是否为AVL树,我开始的思路就用一个递归记深度,一个递归判断是否为AVL树
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
const int N = 129;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int val): val(val), left(0), right(0) {}
};
int treeDeep(TreeNode* root, int d = 0) {
if (!root) {
return d;
}
return max(treeDeep(root->left, d + 1), treeDeep(root->right, d + 1));
}
bool isAVL(TreeNode* root) {
if (!root) return true;
return (abs(treeDeep(root->left) - treeDeep(root->right)) <= 1)
&& isAVL(root->left)
&& isAVL(root->right);
}
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->right->left = new TreeNode(4);
root->right->left->left = new TreeNode(5);
printf("%d\n", isAVL(root));
return 0;
}
第三题:一个旋转的有序数组,求最小的值,比如12345 => 34512,最小值1。剑指offer原题,思路就是二分。
function min(array) {
let left = 0, right = array.length - 1;
if (array[left] < array[right]) return array[left];
while (left < right) {
let mid = parseInt((left + right) / 2);
if (array[mid] > array[left]) {
left = mid + 1;
} else if (array[mid] < array[right]) {
right = mid;
} else {
left ++;
}
}
return array[left];
}
console.log(min([3,4,5,1,2]))
然后三道题大概20分钟吧就完事了,然后面试官看我做的挺快的,就给我出了第四题
第四题:求序列的一个子序列的最大和,比如[-1,2,3,4,-5], 那么子序列就是[2,3,4],最大的和为9
当时是***了,记得以前做过这道题,然后以为是动态规划来解,就一直按照动态规划的思路去做,然后还没做出来,就给他写了一个暴力的做法(ノへ ̄、)
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1000000;
int dp[N];
int maxSum(int array[], int n) {
memset(dp, 0, sizeof(dp));
dp[0] = array[0];
for (int i = 1; i < n; i++) {
dp[i] = dp[i - 1] + array[i];
}
int _max = -99999999;
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (_max < dp[j] - dp[i]) {
_max = dp[j] - dp[i];
}
}
}
return _max;
}
int main() {
int arr[100] = {-1, 2, 3, 4, -5};
printf("%d\n", maxSum(arr, 5));
return 0;
}
当然这是超时的解法,回去和同学交流了一下,发现这道题其实直接for循环一遍就能求出结果o(TヘTo),果然自己还是菜啊
正确的解法:
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
int maxSum(int array[], int n) {
int sum = 0, _max = -9999999;
for (int i = 0; i < n; i++) {
sum += array[i];
if (sum < 0) {
sum = 0;
}
if (_max < sum) {
_max = sum;
}
}
return _max;
}
int main() {
int arr[100] = {-1, 2, -1, 3, 4, -5};
printf("%d\n", maxSum(arr, 5));
return 0;
}
当然面试的时候,面试官看我卡第四题卡挺久的,就让我去优化一下第二题,说我两个递归写有点不好,要我一个递归写,自己试了试,没写出来,就还是写了两个递归的方法┭┮﹏┭┮,果然自己还是菜啊。最后面试官跟我说前三道题答得挺好的,就是第四题写的不算太好。。。。
腾讯四面(视频面试):
其实自己觉得自己二面面的不太好,但腾讯居然还是给我三面了。记得三面是安排到了晚上9点半,然后面试官迟到了半个点,差不多晚上十点多才开始面试╥﹏╥...
面试官开始要我自我介绍,然后要我写大数相乘,当时我给面试官说,如果我用python,只需要像下面这样就可以实现大数相乘了
def multiply(a:int, b:int) -> int:
return a + b
然后用Java的话,直接用BigInteger类就可以了,然后面试官说不让我用语言的特性,不用别人的包,还要我最好用C++写(。﹏。),虽然当时挺想用JavaScript写的,当然用C++也不难,就是模拟手算过程,就是类型转换有点麻烦。
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
void frontFill(string &a, int n) {
while (n --) {
a = "0" + a;
}
}
void backFill(string &a, int n) {
while (n --) {
a += "0";
}
}
int char2Int(char ch) {
return ch - '0';
}
string int2Str(int i) {
string str;
str.push_back(i + '0');
return str;
}
string add(string a, string b) {
int maxLen = a.length() > b.length() ? a.length() : b.length();
frontFill(a, maxLen - a.length());
frontFill(b, maxLen - b.length());
string result;
int acc = 0;
for (int i = maxLen - 1; i >= 0; i--) {
int cur = char2Int(a[i]) + char2Int(b[i]) + acc;
if (cur >= 10) {
acc = cur / 10;
cur = cur % 10;
} else {
acc = 0;
}
result = int2Str(cur) + result;
}
if (acc) {
result = int2Str(acc) + result;
}
return result;
}
string multiplyOne(const string &a, int n) {
string result;
int acc = 0;
for (int i = a.length() - 1; i >= 0; i--) {
int cur = char2Int(a[i]) * n + acc;
if (cur >= 10) {
acc = cur / 10;
cur = cur % 10;
} else {
acc = 0;
}
result = int2Str(cur) + result;
}
if (acc) {
result = int2Str(acc) + result;
}
return result;
}
string multiply(const string &a, const string &b) {
string result = "0";
for (int i = b.length() - 1; i >= 0; i --) {
string temp = multiplyOne(a, char2Int(b[i]));
backFill(temp, b.length() - i - 1);
result = add(result, temp);
}
return result;
}
int main() {
string a = "12345";
string b = "12345";
cout<<multiply(a, b)<<endl;
return 0;
}
不得不说,牛客网的在线编辑器,太差了,一点变量提升都没有,写出变量名、方法名都不给提升,反正我前前后后不断的找错误、调bug,差不多20分钟还是给他写完运行了(/▽\)。
然后还给面试官讲了一个分治的方法,就是AB * CD 等于 (A * 10^(k) + B) * (C * 10^(k) + D)等于 (A * C * 10^2k) + (A * D * 10^k) +(B * C * 10^2k) + (B * D * 10^k),说白了就是将两个数字字符串不断的切成两半在用上面的公式去算每一部分,就是分治的思想,递归的过程,然后由于时间关系就没给他实现了,毕竟宿舍大晚上的还会熄灯。。。
接下来面试官还问了我一些设计模式,比如命令模式,不得不说命令模式我是多久没用过了,就跟面试官说,命令模式在JavaScript中并不常用,所以就给面试官讲了两个常用的设计模式,比如发布订阅模式、观察者模式,然后就要我实现这两个设计模式,先是写了发布订阅,观察者他就没让我写了。
class Event {
constructor() {
this.eventPool = {};
}
on (event, callback) {
this.eventPool[event] ? this.eventPool[event].push(callback) : this.eventPool[event] = [callback];
}
emit (event, ...args) {
this.eventPool[event] && this.eventPool[event].forEach(cb => cb(...args));
}
}
const event = new Event();
event.on("err", console.log);
event.emit("err", "have error");
然后看我在简历上写了了解flutter就问我跨平台应用是怎么实现的,然后问了问JavaScript的闭包是咋回事,get和post的区别,常见的http状态码等一些比较简单的问题,最后他问了我一个比较开放性的问题,就是要我在电影院里建厕所,反正当时没理解题意,就照着自己的思路答,面试官也在一边笑,然后等我说完后,面试官就开始说他的思路,其实这不是一个简单的建厕所问题,而且微信服务器部署的问题,部署在哪,需要多少服务器是最好的,然后要我考虑正常情况下和高峰情况下需要多少服务器等等,最后就是我要多结合一些生活中的例子,其实互联网的很多思想都是来自于生活的。。。
腾讯HR面(电话面试):
差不多过了一个星期吧,HR终于给我打电话了,先是自我介绍,然后问我为什么学前端,学前端多久了等等,问我是如何选择实习的公司的,我说首先要看是什么公司,比如像腾讯这样的大公司我会优先考虑,然后在看什么部门,然后看同事是不是都是那种好说话的同事等等,然后还问了我的爱好,问了我性格啥的,问我碰到问题一般会怎么解决,还问我希望在腾讯收获些什么,我回答的比较low,就是平常自己一个人学前端太辛苦了,没有太多的方向感,只希望去到腾讯,和腾讯的前端大佬交流,跟着大佬学习(✿◕‿◕✿)。腾讯HR面试大概15分钟吧就面完了,感觉有点快。不过第二天还是给我下offer了,开心[]( ̄▽ ̄)*。
现在是拿了两个offer吧,字节跳动的直播中台部门,和腾讯的企业微信,现在感觉有点选择困难了,感觉两个都是比较好的部门。当然还想继续保研,毕竟自己成绩也是够的(●'◡'●)。