网易2021暑期实习 游戏开发 一面

笔试是在5月6日晚间完成的,试卷标题上写着“零散批”,估计是因为投递简历太晚了。

笔试情况前文已经说过,3题我做出来俩。11日收到预约面试通知,让我选择一个时间进行面试。网易的面试预约流程是我感觉最好的,首先是可供选择的时间比较多,有4个,分别是12日和13日这两天的上午9:30和10:30;其次是操作比较简单,去官网选一个时间就行,别家的面试都是打电话/发邮件,用自然语言沟通。

面试流程也如同预先通知的那样,是半小时代码+一小时交流。

算法

一共出了3个算法题。

题目1:数组最大距离

这是一开始那半小时的代码题。

定义两个数组A, B之间的距离 max ⁡ { ∣ a − b ∣ ∣ a ∈ A , b ∈ B } \max\{ |a-b|| a\in A, b\in B\} max{abaA,bB},即两数组里各挑选一个元素,差值的绝对值的最大值。
实现一个函数,输入m个已经按升序排好的数组,输出它们之间的距离的最大值。

这题看起来是出乎意料的简单,只要把最大的和最小的都找出来就可以了吧。而且顺序已经都排好了,找到他俩只需要 O ( m ) O(m) O(m)的时间遍历一遍所有数组的首尾元素。

然后我发现没有处理一个特殊情况,就是最大和最小元素在同一个数组里。于是我引入了次大和次小元素。由于最终使用的最大值不可能是某个数组里的次大值(肯定不如用最大值好),小的方面同理,所以这里的次大/次小指的是所有数组的最大/小值里的次大/小值。

很快我就写完了,半小时还剩下大概15分钟。我看来看去,想不出可以改正的地方,面试官也还没发起语音通话,于是剩下的时间就磨蹭过去了。

后面面试官问我思路,我就如实告知。

题目2:等概率随机排列

输入一个数组,输出它的一个随机排列。要求该数组的所有排列能等概率地出现。

我一看是大喜过望,因为几个月之前看《算法导论》的时候,开头就讲到这个问题,并且讲到高德纳提出的一种非常高效的算法:洗牌算法。这算法过于巧妙,以至于我后来又看了好几次,一直记到今天。

于是我很快写了大概的代码:

void RandomShuffle(vector<int>& m){
	int n = m.size();
	for(int i=0; i<n; i++){
		int j=rand(i, n);
		swap(i, j);
	}
	return;
}

实际上很有瑕疵,比如我不知道在{i, i+1, ……, n-1}里取一个随机数具体应该怎么写,比如我swap的参数错了……

不过面试官没有纠结这些细节,而是让我用数学的方法证明这样是对的。

我当初看这个算法的证明看了不少次,印象还算深刻。分情况一讨论,很快就说明了每个数字出现在每个位置的概率都是 1 / n 1/n 1/n

我突然又想到,即使每个数字出现在每个位置的概率都是 1 / n 1/n 1/n,结果也未必会等概率地输出所有排列。
比如,一个算法把所有元素都往后移动随机位数,越界的就循环地补到前面,这样也能满足上面说的概率条件,但能输出的排列只有 n n n个。《算法导论》书上有这道习题,我看到解答时惊讶不已,于是明白了应该严格证明所有排列都可能等概率地输出。

但面试官并没有继续追问,我也只是想到了证明的不足,并没有想到怎么完善……就没再多嘴)

题目3:设计定时器

实现两个函数:
void RegisterFunc(int time, void* Function);
该函数输入一个绝对时间和一个函数指针,功能是将一个函数注册进定时器。
void UpdateTimer(int time);
该函数输入当前的时间,功能是触发定时器,将所有已经注册进定时器的、对应的绝对时间小于当前时间的函数拿出来调用。如果有多个函数被找到,则按时间顺序调用它们。
实现基本功能后,考虑两种极端情况:RegisterFunc被频繁调用;UpdateTimer被频繁调用。

具体怎么调用的细节应该是不重要的,最主要的是如何降低两种操作的时间复杂度。那么核心的问题就是如何设计定时器的数据结构,使得每次注册和每次触发都能很快完成。

我首先想到的是队列,因为已经注册的任务是按照时间顺序调度的,和队列的性质差不多。
队列的缺点也很明显:要实现在中间插入而非尾部插入,我只能想到用链表,那么每次插入都可能要 O ( n ) O(n) O(n)的时间;每次触发也要从前往后遍历,时间也可能要 O ( n ) O(n) O(n)

那么能不能在链表之外多一些指针,指向链表中某些节点,每两个指针之间都有固定的时间间隔呢?这恐怕还是同样级别的时间复杂度,只是常数项会随着额外指针的密度增加而降低。

如果要降低时间复杂度的级别,似乎要给这些额外指针之外再增加指针,一层层不断地加,一直加到只有一个为止。我隐隐感觉,这对应某种树的结构,像是n叉搜索树之类的……但这种高级数据结构我了解的特别少,于是只能勉勉强强说思路说到这里为止。

小题:快排的原理

这也是老题目了,没什么好重复的。无非是说说快排的过程,最坏情况,如何避免,中间元素的选择方法……之类的罢了。

操作系统

一如既往地不会。

但这次面试官甚至没有提问,而是让我知道啥就说啥……我就说了堆和栈的区别和这种区别的意义之类的比较基础的内容。

网络

又是经典题目:三次握手,四次挥手。我虽然没学过计网,但这题我都快背烂了,因为问的实在是太多了……

其他

让我介绍一下自己最熟悉的项目,问了一下其中的细节。这基本也是每次面试都会问到的题目,我也越答越熟练了。
不过这次面试官借题发挥。他问我,如果你的应用要同时给成千上万用户推送的话,服务器容易宕机,有什么办法解决吗?我一时语塞,实在没辙,勉强说了个“把用户分类”的方法。
关于游戏:面试官并没有提问太多,只是知道我喜欢玩炉石,说了一句“炉石是需要很多计算的”。我立即有很多话想滔滔不绝地说出来,比如炉石在技术和运气之间做到很好的平衡啦,炉石给硬核玩家准备的特殊环节啦……但我说到一半,感觉他似乎不太想听,只是想随便提一下而已……于是就住口了。
我对炉石的架构有这么多理解,也许我应该去试试游戏策划的职位,而非开发工程师。
初次之外,几乎没有关于游戏的问题。我还有很多关于游戏的优缺点的头头是道的分析没说出来呢。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值