未处理的面经-网易互娱游戏研发

作者:兵长一米六
链接:https://www.nowcoder.com/discuss/232268?type=all&order=time&pos=&page=1
来源:牛客网


第一次开发类面试的经历,控制不住的紧张啊,形式是视频面试,全程1h

没有自我介绍,开始面试后先做了一道随机数的编程题: 给了玩家列表,随机选出N个玩家
 1 //给了玩家列表,随机选出N个玩家
 2 #include 
 3 #include 
 4 #include 
 5 #include <set>
 6 #include 
 7 using namespace std;
 8 
 9 //会出现重复,所以使用set
10 set<int> getRandomPlayers(const vector<int> &players, int n)
11 {
12     set<int> res;
13     srand((unsigned int)time(NULL));
14     while (res.size() < n)
15     {
16         int m = rand() % players.size();
17         res.insert(players[m]); //C++17
18     }
19     return res;
20 }
21 
22 int main()
23 {
24     vector<int> test = {1, 5, 999, 89076, 321, 23876, 12345, 2, 4, 654, 567, 1001};
25     auto set = getRandomPlayers(test, 4);
26     cout << "选出的用户: ";
27     for (int i : vec)
28         cout << i << "  ";
29 
30     return 0;
31 }
View Code
然后开始问问题,中间穿插着又做了一个编程题,最后结束时也是一个动态规划的问题
写一下问到的知识点吧:
C++:

C++的特性:

1.封装:从食物中抽取共性,抽象成为类,将类的属性和对于属性的操作方法组合成为一个类,即是封装;

2.继承:通过基类派生子类的方式,可以实现代码的复用;

3.多态:静态多态和动态多态

静态多态:函数重载(函数重载需要注意二义性)和模板。模板又分为函数模板和类模板,是一种泛型编程方式,

template  

ret type fucname(T t1, T t2...)

{...}

T相当于再占位,等待具体的类型来替换他(实例化它)。一般所见到的容器和一些泛型算法都是模板,STL中大量使用了模板。

类的默认生成成员

构造、析构,拷贝构造和拷贝赋值函数。

拷贝构造干了什么?

使用一个已存在的对象去实例化一个对象,比如:

 1 class A{
 2 public :
 3     A();
 4     ~A();
 5     A* A(const A&a){
 6         m = a.m;
 7     }
 8 private:
 9     int m;
10 }
View Code

还涉及到深拷贝和浅拷贝的问题。

结合内存对齐的类大小问题

模板实例化

显示实例化和隐式实例化

特化和偏特化

模板有部分实例化和完全实例化两种类型,在C++primer中后面章节中有介绍。

实例化即是将模板中的类型集体化,这里说的应该是特化,那么就是把所有的模板类型都具体化,可以实例化为具体的int/double...类型或者实例化为容器类型都可以,模板实例化其实是编译器的工作,如果想要固定部分参数或者返回值的类型,可以使用实例化,但完全实例化也就失去了模板的意义。

操作系统:

虚拟内存

虚拟内存和物理内存对应,是OS中概念。物理内存是不变的,但我们可以通过在运行程序时,只将一部分数据装入内存中,在用到其他程序或者数据时,再将它们从外存/辅储中置换进来。更加具体一点:当CPU需要访问某页数据或者程序时,先从该数据的逻辑地址中拿到逻辑的组号和组内的逻辑地址,先判断该组是否在内存中,如果在,直接去访问,通过地址转换表拿到对应的物理组号,然后根据组内的逻辑地址访问数据。如果找不到该组,那么就需要从从辅存中将该页置换进入内存中,如果内存中有空余页,那么直接置换,如果没有,那么遵循一定规则将某些也置换出内存。具体的置换方法:先进先出、最近最少使用、最佳算法(预估最长时间才会使用的页调出内存,是一种理想的算法)。

动态链接和静态链接

是程序整个编译过程中的一盒环节,链接的两种不同方式。程序从编辑,预编译,编译得到汇编代码,然后经过汇编得到二进制文件,再经过链接得到可执行文件。而静态连接是将用到的函数和库直接装入可执行文件中,动态链接不是,他和可执行文件是分离的,再运行时用到才去该文件中寻找调用。

二者的优缺点:

1. 静态链接使得可执行文件比较臃肿,而动态链接的可以节省存储空间;

2. 静态链接会存在重复装入的问题,如果多次调用某函数,那么就会多次装入该函数,所以需要使用ifndef之流来改善,而动态链接不需要(运行时动态调用);

3. 扩展和更新:显然动态链接的扩展性要好于静态。只要更换动态链接库即可,然只要发生更改,静态链接库还需要重新编译源程序。

4. 在Windows中分别是*.lib,*.dll;而在Linuxz中是lib*.a和*.so

计算机网络:

TCP、UDP区别、所在层(传输层),ping用哪个

1.有无连接;tcp有连接,udp无连接

2.是否可靠;tcp可靠,udp不可靠

3.那种协议;tcp流式协议,udp数据报式协议

4.发送速率:就拿单次数据请求来说,tcp需要:2*RTT+SPT,udp只需要RTT+SPT。

5.发端和收端的关系:tcp发端发送次数和收端接受次数没有数量关系,udp发送一次就必须接收,且如果接收缓冲区小于数据报的长度,那么会发生截断,多余数据丢失;tcp不会,双方都维护有拥塞窗口,会动态的进行流量控制。

6.适用范围:广播多播必须使用udp,大量数据一般使用tcp,如文件传输;一般的音视频传输也使用udp。

ping使用ICMP协议

数据结构算法:

红黑树

红黑树是一种平衡二叉树,当然他不像AVL树那样,要求左右子树深度之差不超过1,而是一种折中方案。

他有以下特性:

节点有颜色,且非黑即红;

根节点为黑色

叶子节点为黑色

红色节点子节点必须为黑;

从根节点到叶子节点路径上的黑色节点个数必须要相等;

由于上面的特性,使得红黑树较为平衡log(n),他没有AVL树那样平衡,但是可以通过较少的旋转和变色来维持平衡,总体性能上要好于AVL树,所以STL中的map/set等都使用了红黑树。

查找插入和删除最坏都为O(log(n))

排序算法

一般的有冒泡、插入、选择、快排、堆排序、归并排序

稳定的排序算法有插入、冒泡和归并排序;

最快的算法一般都是:O(nlogn),快排、归并排序、堆排序;其他的平均时间复杂度都是O(n2);

3min写个快排(自己加的)

 1 void quickSort(vector<int> &nums, int l, int r)
 2 {
 3     if (l >= r)
 4         return;
 5     int i = l, j = r + 1;
 6     int key = nums[l];
 7     while (true)
 8     {
 9         while (nums[++i] < key)
10         {
11             if (i == r)
12                 break;
13         }
14         while (nums[--j] > key)
15         {
16             if (j == l)
17                 break;
18         }
19         if (i >= j)
20             break;
21         int tmp = nums[i];
22         nums[i] = nums[j];
23         nums[j] = tmp;
24     }
25     int tmp = nums[l];
26     nums[l] = nums[j];
27     nums[j] = tmp;
28     quickSort(nums, l, j - 1);
29     quickSort(nums, j + 1, r);
30 }
View Code

拓扑排序?

 (没见过)

深度搜索、广度搜索

 

编程题:

给了一个整数,得到一个逆序的整数

 1 //整数逆序1,使用to_string
 2 long long reverseInteger(int n)
 3 {
 4     long long res = 0;
 5     string str = to_string(n);
 6     //12345->54321
 7     for (int i = str.length() - 1; i >= 0; i--)
 8     {
 9         res = res * 10 + (str[i] - '0');
10     }
11     return res;
12 }
View Code
 1 //整数逆序1,不使用其他函数,但需要辅助队列
 2 long long reverseInteger(int n, int flag)
 3 {
 4     long long res = 0;
 5     //必须要一个辅助容器,stack就不错
 6     queue<int> q;
 7     while (n)
 8     {
 9         q.push(n % 10);
10         n /= 10;
11     }
12     while (!q.empty())
13     {
14         res = res * 10 + q.front();
15         q.pop();
16     }
17     return res;
18 }
View Code

从左上到右下,找到和最小的路径(动态规划) 

 1 //使用极限电量来完成最短路径和(每一步都只能往右或者下走)
 2 int getShorstLoad(vectorint>> &m)
 3 {
 4     int row = m.size(), col = m[0].size();
 5     vectorint>> dp = m;
 6     for (int i = 0; i < row; i++)
 7     {
 8         for (int j = 0; j < col; j++)
 9         {
10             if (i == 0 && j == 0)
11                 dp[i][j] = m[0][0];
12             else if (i == 0)
13                 dp[i][j] = m[i][j] + dp[i][j - 1];
14             else if (j == 0)
15                 dp[i][j] = m[i][j] + dp[i - 1][j];
16             else
17                 dp[i][j] = m[i][j] + min(dp[i - 1][j], dp[i][j - 1]);
18         }
19     }
20     return dp[row - 1][col - 1];
21 }
View Code
总结一下:自我感觉表现得很差,编程题发挥的太差,面试官一直在引导我,还很耐心地等我,自己还是各种卡,甚至连函数的使用方法都忘了,面试时敲代码和平时敲代码果然差距很大啊,脑袋就像不转了一样,然后各种忘。虽然自己表现的太差,但也是自己的一次宝贵的经历,结束啦,好好准备下一次吧。

你可能感兴趣的:(未处理的面经-网易互娱游戏研发)