七擒七纵之腾讯面经

这次面试可以用恐怖来形容,比阿里、字节都难多了。更离谱的是面试过程中竟然串台了,同时接到2个面试官电话,同一个号码。真不知道腾讯是怎么安排的,真假面试官,我也不知道我这面的有没有问题。

总之这次面试就非常难,非常离谱。


1. 腾讯云后台开发岗

面试开始还是先自我介绍,因为项目中提到了影响力排名,就被问到了影响力排名算法,然后引申出如何找出k条最大的记录,我答了用优先队列和排序。

然后问了:

数据库处理大规模查询操作的优化方法

高并发下的自增主键造成数据库负载过大的问题

c++的纯虚函数

冒泡排序(这我竟然一时愣住了)

TCP头里有哪些内容(这我哪记得住)

TTL是干啥的(避免回环)

Linux命令(tail, ls, grep, touch

Linux touch命令用于修改文件或者目录的时间属性,包括存取时间和更改时间。若文件不存在,系统会建立一个新的文件。


3.10 更新

上次面试第二天一查,流程已终结,我还厚着脸皮去群里问了下昨晚那情况会不会有影响,hr回应说都是一个部门的结果没影响,这回是坐实挂了。。。


3.16 更新

前两天又收到了游戏客户端开发岗的面试通知,想不到这么快就被捞起来了。这次一定要好好准备。


2. 北极光工作室游戏客户端开发岗

今天接到面试电话,才知道是北极光工作室(好像都没啥名气),主要是移动端开发,base上海。

这面试官也没让我自我介绍,上来就说看我成绩还不错,今后是不是考虑读研,我说挺想直接工作的,如果能进这样的大厂就不读研了。他反问我像你这样成绩不错的不都会去读研吗?(看来上来他就没抱希望招我)

然后就开始问我项目了,差不多让我逐一介绍了差不多每个项目(课程设计项目也没放过),问了团队有几个人,你担任了什么工作。有几个项目是C++写的,他就顺势问了下C++的了解程度,问了下智能指针基类中的析构函数为什么一般定义为虚函数

然后问了对游戏开发有什么了解,我如实回答了只是玩过。。。又问了对图形渲染,游戏引擎有什么了解,我说了下用过WebGL,讲了一下流水线绘制过程。

面试就差不多到此为止了,我问了下部门的主要工作,主要是移动端开发,还有unity引擎的魔改,主要用到C#和C++。

至此就结束了,连QA环节都只有20分钟,专业课知识一点都没问,白费我那么多时间准备了。

感觉这部门也挺卑微的,这回总不会这门快就给我踢了吧?


An hour later…

一刷新网页,好家伙,又凉了。

你部门既然不要我,捞我出来作甚?(腾讯好感度-10086)


3.19 更新

这回又是广州的微信部门来电话了。。。不会吧,不会吧,不会真有人连挂三次吧。

3. 微信小游戏后台开发

这回是视频面试,有手撕代码环节,但没问项目。

这次简直太难了,果然腾讯很注重基础,问了很多底层细节。

  • map的底层实现(红黑树)

  • C++还有什么数据类型(我答unordered_map)

  • 哈希表如何实现,表大小如何设置,是否需要扩容。(扩容我不会了)

    会扩容,增加桶的数量,rehash

  • 手撕代码:LRU实现

    幸亏考前刚好看过,知道是用哈希表双向链表实现,但面试官特别注重细节,指出了我get()操作后没有移动位置,指针没有初始化,没写析构函数等等。。。

  • static作用(我忘了还能修饰函数)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 1.h
    static int a;

    //1.cpp
    #include"1.h"
    // 2.cpp 中能否访问

    //2.cpp
    #include"1.h"
    //2.cpp 中能否访问

    include的过程我竟然都说错了(应该是把头文件中的内容替换过来)

  • C++传参机制,比如printf("%d,%d,%d",1,2,3)如何知道有几个参数,数据类型是什么(我只记得编译原理里好像说过是用栈传的,具体原理就不知道了)

    C/C++函数参数的传递方式有三种:值传递(pass by value)、指针传递(pass by pointer)、引用传递(pass by reference)。

    C/C++函数参数的传递通道是通过堆栈传递,默认遵循__cdecl(C声明方式),参数由调用者从右往左逐个压入堆栈,在函数调用完成之后再由调用者恢复堆栈。

    指针传递和引用传递在机制是一样的,都是将指针值(即地址)压入栈中,调用函数,然后恢复栈。

    值传递会形成一个拷贝。如果是一个自定义的结构类型,并且有很多参数,那么如果用值传递,这个结构体将被分割为非常多个32Bit的逐个拷贝到栈中去,这样的参数传递效率是非常慢的。所以结构体等自定义类型,都使用引用传递,如果不希望别人修改结构体变量,可以加上const修饰,如(const MY_STRUCT& _value);

  • udp/tcp 区别,udp能否实现可靠传输,udp包大小

    1、添加seq/ack机制,确保数据发送到对端

    2、添加发送和接收缓冲区,主要是用户超时重传。

    3、添加超时重传机制。

    送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。

4.PCG运营开发

3.25

辣鸡tx真的越来越离谱了,今天这上来都不自报家门了,要不是我主动问他都不知道我面了个啥。真是槽点太多。。。

先记下有用的:

  • 给两个字符串,计算日期差(我用的python,datetime一减就行)
  • 列举10个Linux命令
  • C++析构函数有什么用
  • 貌似就没了。。。。

当他问了“你比较熟悉Java吧”,我回了否就知道大概又没戏了。

视频面他也没开摄像头,声音听起来像是没睡醒,那边一直有电话声音,说有人找他。

他问我对前端了解多少,我打出个问号,我这面的不是后端吗???

又问我了解大数据吗?我说不了解,那真的无了。。。

你同学怎么评价你,用3个词形容一下,兴趣是什么????这是HR面吗?实在没的问了吗?

最后也没留提问环节,还是我主动问的才知道他是PCG大数据部门。。。

总结:体验极差,希望不要有下次了!!!只发邮件不打电话,一律是冲KPI!

5.微信支付

4.8

时隔一周多终于又有部门捞我了,这次又是只给我发了邮件,没打电话,根据前几次的经验,我还是犹豫了一下要不要接受,最后点了时间不合适,在留言框里表明了我的态度,冲KPI的,免谈!果然,晚上打电话来了,表明了他的诚意,就接受了。

今天下午2点通过腾讯会议面的,写代码用的腾讯文档,面试流程比较短总共40分钟,2题代码,15分钟,说是2选一,我写了一道半。

1
2
3
4
5
6
7
8
9
/*
1. 如何利用下面的随机源生成0-10000之间的随机数?
unsigned char rnd();//返回[0,255]闭区间的随机数
*/
int rnd10000(){
int res;
while(res=rnd()*256+rnd() > 60000);
return res % 6;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
2. 嵌套数组的遍历,实现hasNext和next函数。注意:
a) 一个NestedVector实例中的数据只可能是int数组或NestedVector数组
b) 根据isNested判断属于哪种类型
c) 可以在class内外增加变量或函数
d) 遍历时空数组需要跳过
class NestedVector{
public:
//Have
bool isNested();
const vector<int>& getElement();//可能为空
const vector<NestedVector>& getNest();//可能为空
//TODO
bool hasNext();//是否还有下一个元素
int next();//返回当前的元素,然后移动到下一个元素
private:
vector<int> intList;
vector< NestedVector> nvList;
};
void main(){
NestedVector nv;
…//向nv写入数据
while(nv.hasNext()) cout << nv.next();
}
以下例子均需输出1 2 3 4:
● [1,2,3,4]
● [[1,2],[3,4]]
● [[],[1,2,3,4]]
不存在[1,2,[3,4]]这种情况
*/


// 类似 力扣 341. 扁平化嵌套列表迭代器 https://leetcode-cn.com/problems/flatten-nested-list-iterator

// ANS: 我没写完就大致说了下思路

class NestedVector{
public:
//Have
bool isNested();
const vector<int>& getElement();//可能为空
const vector<NestedVector>& getNest();//可能为空
//TODO

stack< pair<vector<NestedVector>::iterator, vector<NestedVector>::iterator> stk;

NestedVector(){
if(isNested()){
stk.emplace( nvList.begin(), nvList.end());
}
}
bool hasNext()/是否还有下一个元素
{
while(!stk.empty()){
auto p=stk.top();
if(p.first==p.second){ //末尾
stk.pop();
continue;

}

if(p.first->isNested()==false){
if(p.first->intList.size()>0)return true;
else return false;
}else{
}
}

}
int next();//返回当前的元素,然后移动到下一个元素
private:
vector<int> intList;
vector< NestedVector> nvList;
};
void main(){
NestedVector nv;
//向nv写入数据
while(nv.hasNext()) cout << nv.next();
}

最后我斗胆问了下能过吗,面试官说我答得不错,但决定不在他手上。


没过多久又收到了初试通知,不知道是挂了又被捞了还是进了第二轮。祈祷放我过一次吧!!!

6.微信支付 二面

4.12

问了下面试官,还是微信部门,应该是二面了吧。

今天的面试流程比较常规,提问+做题。只是我自我介绍还没讲完就被打断提问了。

提问内容:

  1. 对HTTP协议的理解

  2. 访问一个url的过程

  3. TLS连接过程

  4. map和hash_map区别

  5. 数据库查询优化

  6. 主键索引和唯一索引区别

  7. 数据库隔离级别,解决方法

  8. 红黑树插入最多移动几个节点(两次)

    h<=2log(n+1)

    (1)每个节点或者是黑色,或者是红色。
    (2)根节点是黑色。
    (3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
    (4)如果一个节点是红色的,则它的子节点必须是黑色的。
    (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

  9. hash表解决冲突方法

    1. 开放地址法
      1. 线性探测再散列
      2. 二次探测再散列
      3. 伪随机探测再散列
    2. 再哈希法
    3. 链地址法
    4. 建立公共溢出区
  10. c++程序执行main函数前的过程

    1. 设置栈指针
    2. 初始化static静态和global全局变量,即data段的内容
    3. 将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容
    4. 运行全局构造器,估计是C++中构造函数之类的吧
    5. 将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数
  11. 线程进程区别

  12. 协程是什么

    最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

    不需要多线程的锁机制

  13. 线程间通信方法

    1. 匿名管道通信:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系
    2. 高级管道通信:将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
    3. 有名管道通信: 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
    4. 消息队列通信:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    5. 信号量通信:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
    6. 信号:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
    7. 共享内存通信:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
    8. 套接字通信( socket ) : 套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

手撕代码:数字转人民币大写

7.微信支付 三面

4.14

上来就一道编程题,合并列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//两个有序(从小到大)单链表,合并为一个有序的单链表
struct LinkNode {
int value;
struct LinkNode * next;
LinkNode(int v=0){value=v;next=nullptr;}
};

struct LinkNode * merge( struct LinkNode * firstLink, struct LinkNode * secondLink ){
LinkNode* head=new LinkNode();
head->next=nullptr;
LinkNode* p1=firstLink;
LinkNode* p2=secondLink;
LinkNode* newhead=head;
while(p1!=nullptr&&p2!=nullptr){
if(p1->value > p2->value){
head->next=p1;
p1=p1->next;
}else{
head->next=p2;
p2=p2->next;
}
if(head->next==nullptr || head->value!=head->next->value){
head=head->next;
head->next=nullptr;
}

}
if(p1==nullptr)head->next=p2;
else head->next=p1;

LinkNode* res=newhead->next;
delete newhead;
return res;
}


#include <iostream>
using namespace std;


void printLink(LinkNode* p){
cout<<"[";
while(p!=nullptr){
cout<<p->value<<" ";
p=p->next;
}
cout<<"]\n";
}
int main() {
LinkNode* p1=new LinkNode();
LinkNode* p2=new LinkNode();
LinkNode* h1=p1;
LinkNode* h2=p2;
for(int i=10000;i>0;i-=2){
h1->next= new LinkNode(i);
h1=h1->next;
h1->next= new LinkNode(i);
h1=h1->next;
}

for(int i=10;i>0;i-=1){
h2->next=new LinkNode(i-1);
h2=h2->next;
}

printLink(p1->next);
printLink(p2->next);
LinkNode* p3=merge(p1->next,p2->next);
printLink(p3);

}
  • 主键和唯一索引区别
  • order by
  • 线程间通信

4.26 今天终于OC了,躺了躺了

4.27 收到offer邮件,已接受

七擒七纵之腾讯面经

https://blog.luzy.top/posts/3274961897/

作者

江风引雨

发布于

2021-03-09

更新于

2023-01-10

许可协议

CC BY 4.0

评论