1. 程式人生 > >網易互娛 遊戲研發 暑期實習面試面經

網易互娛 遊戲研發 暑期實習面試面經

# 前言 昨天面了網易互娛的遊戲研發工程師,回想下似乎問的問題並不多,整體也就 5 個問題,但每個問題展開之後裡面的量好像也不少,現在整理一下,順便解決下面試中沒答上來的地方。 # 面試題 先是自我介紹。。。。。面試官瞭解到我對 Python 更加熟悉一些,於是問了比較多的 Python 相關的問題。 ## Python 中如何實現類成員的 public、private、protected 面試官:在 C++、Java中,定義一個類,其成員可以申明為 public、private、protected, 那麼在Python 中如何實現類成員的 public、private、protected 答:Python 語言並不存在控制訪問,所以無法直接定義類成員的 pubilc、private等屬性,一般情況下是通過命名規約來達到這個效果,對於 private 的成員,一般命名以 `_` 開頭,而 public 的則正常命名即可。 面試官:那對於雙下劃線`__`開頭的成員呢? 答:雙下劃線開頭的成員感覺主要是用在類的繼承的時候,如果不想子類直接訪問到父類的這個成員,則可以以雙下滑線開頭。(修正,不僅僅是繼承的時候,在該類中定義了雙下劃線開頭的成員,例項化的物件也無法直接訪問該成員) 面試官:如果我訪問了這個雙下劃線開頭的成員,會報什麼錯誤? 這裡我突然就愣住了,因為之前都沒去嘗試過,愣了一會兒之後,面試官給了些提示,如果你訪問一個變數,但這個變數沒有定義的話,那會報什麼錯誤? 答:應該是變數不存在吧 面試官:那上面那個問題是報什麼錯誤呢? 答:這麼一說感覺應該是變數不存在 面試官:那再問問如果我非要訪問這個雙下滑線開頭的成員,要怎麼做? 這裡真就不會了 orz 現在來補一下 ```python ''' @Description: @Author: 妄想 @Date: 2020-05-29 15:28:30 @LastEditTime: 2020-05-29 15:32:52 @LastEditors: 妄想 ''' class base: def __init__(self): self.public = 1 self._internal = 2 self.__private = 3 def public_method(self): print('public method') def _internal_method(self): print('internal method') def __private_method(self): print('private method') b = base() print(b.public) print(b._internal) print(b.__private) ``` 執行一下 ![](https://img2020.cnblogs.com/blog/1413964/202005/1413964-20200529153630374-607073576.png) 那我該如何訪問它呢?查了下資料,發現雙下劃線開頭的成員,會被重新命名,變成 `_類名` + 成員名,在這裡就是`b._base__private` ```python print(b.public) print(b._internal) print(b._base__private) ``` 函式也是類似 ## python 修飾器 面試官:瞭解過修飾器嗎? 答:瞭解過 面試官:介紹下 Python 中修飾器(問題大概就是這個意思吧) 答:balabalabala。。。。(大致意思就是減少程式碼重複,封裝成裝飾器方便使用,類似於函式) 面試官:那一個裝飾器的輸入和輸出是什麼呢? 答:輸入?可以是任意的引數吧,這個不是根據實際定義的嗎?(這裡我理解錯了面試官的意思了- - ,因為之前在做 web 後端的時候,用了修飾器來做 token 驗證,當時將 token 作為一個引數使用了)後面在面試官的引導下,反應過來了,輸入和輸出都是函式。 面試官:如果我不採用 @修飾器名稱 的方式來呼叫修飾器,那該怎麼做? 答:我印象中是直接當做函式呼叫就好了,但是好像並沒成功 orz 。。 先來個一般寫法 ```python def foo(f): def inner(): print('inner') return f return inner @foo def bar(): pass bar() ``` 會發現輸出了 inner,然後我當時寫了這樣的呼叫 ```python def foo(f): def inner(): print('inner') return f return inner def bar(): pass foo(bar) ``` 發現沒輸出 orz, 然後就過去了,後來仔細想想,雖說返回的是函式,但只是這個函式名啊,我並沒有呼叫它哪來的輸出啊,菜哭。。 改成這樣就好了 ```python bar = foo(bar) bar() # 或 foo(bar)() ``` ## python 迭代器 面試官:瞭解過迭代器嗎?可以介紹下嗎? 答:迭代器一般是用在對 Python 中的資料結構進行遍歷,比如我現在有一個名為 li 的 List,我想對裡面每個元素進行修改,那就需要遍歷每個元素,這時通過 `for number in li:` 這條語句,便會生成一個迭代器,然後 number 為當前所在位置的元素。 面試官:那這跟直接索引遍歷相比的好處是什麼? 答:(這裡憑感覺答的,也不清楚對不對)1. 按索引遍歷的話首先需要知道這個資料結構的長度。2. 每次遍歷的時候都需要通過索引來獲取這個資料,而通過迭代器可直接獲取到資料。 面試官:那有沒有什麼情況下是不能使用迭代器的呢? 答:這裡我覺得存在刪除操作的時候應該是不能使用迭代器的,如下面這段程式碼, 我想刪除列表中大於 3 的元素 ```python li = [1, 2, 3, 4, 5, 1, 4] for i in li: if i > 3: li.remove(i) print(li) ``` 輸出一下發現結果為 [1, 2, 3, 5, 1] 面試官:那新增的時候呢? 答:新增的情況沒遇到過,不太清楚,但感覺應該也不太行。(個人感覺,一般來說新增是需要滿足某種情況才進行新增,但是在迭代過程中進行新增,會導致迭代器需迭代的元素不斷增加,如果操作不當可能會陷入死迴圈)。 ## C++ 結構體對齊 本以為結構體對齊很簡單的,然而。。我天真了 - - 面試官:那接下來問問 C++ 方面的內容,瞭解過結構體的對齊嗎? 答:瞭解過, balabalabala。。。。 面試官:那來算一下這個結構體的大小吧 ```c++ struct Node { short a; long b; char c; char d; int e; int f; short i; short j; long k; }; ``` ![](https://img2020.cnblogs.com/blog/1413964/202005/1413964-20200529165628885-830562486.gif) 答:(算就算吧),算了一會兒,算出來一個 34 位元組 面試官:怎麼得出來的 答:首先 short 佔 2 位元組, 然後 long 佔 8 位元組, 後面加起來總共是 22 位元組,對齊一下就是 24 位元組,加起來總共 34 位元組。(後來驗證了下,發現自己錯了 orz) 面試官:你確定這裡第一個 short 只佔 2 位元組嗎? 答:balabalabala。。。(我還覺得自己很對,後來下來驗證了下發現自己打錯了 orz) 面試官:這裡作業系統是怎麼讀取資料的?一次能讀兩個位元組嗎? 答:(這裡我已經懵逼了)emmmmm。。。不太清楚。。我記得這裡應該是讀取一個起始位置 + 偏移量來獲取這個資料。 面試官:下去之後有興趣再去了解了解吧 這裡開始補充,發現 mingw64 long只佔 4 個位元組??? ```c++ /* * @Description: * @Author: 妄想 * @Date: 2020-05-29 16:42:59 * @LastEditTime: 2020-05-29 16:54:49 * @LastEditors: 妄想 */ #include #include using namespace std; struct Node { short a; long long b; char c; char d; int e; int f; short i; short j; long long k; }; // 2 + 8 + 22 // 34 int main(){ printf("%d\n", sizeof(Node)); printf("%d %d %d %d %d %d %d %d %d\n", &Node::a, &Node::b, &Node::c, &Node::d, &Node::e, &Node::f, &Node::i, &Node::j, &Node::k); printf("char:%d, short:%d, int:%d, long:%d, long long:%d\n", sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long)); return 0; } ``` 看一下輸出 ![](https://img2020.cnblogs.com/blog/1413964/202005/1413964-20200529170758042-1568756685.png) 這個 long 只佔 4 位元組有點迷,沒辦法,就先改成 long long 吧。 可以發現,變數 b 的起始位置是 8 而不是 2,e 的起始位置是 20 而不是 18。 查了下相關[部落格](https://zhuanlan.zhihu.com/p/26122273): 1. 結構體中元素需被放置在自身對齊大小的整數倍的位置上 2. 如果結構體的大小不是所有元素中最大對齊大小的整數倍,則結構體對齊到最大元素對齊大小的整數倍,填充空間放置到結構體末尾 ## 排序演算法 面試官:接下來問問演算法方面的東西吧,說一說快排的流程。 答:(很尷尬。。。已經很久沒有接觸過排序演算法了,近期準備面試也沒看過排序方面的東西,所以想了一段時間,好歹還是想起來了) balabalabala。。。。 面試官:那時間複雜度呢? 答:最差 $O(n^2)$ ,平均 $O(n\log n)$ 面試官:什麼情況下最差呢? 答:陣列完全逆序排序的時候 面試官:那怎麼選取主元能使得快排的效能最好呢? 答:(這個之前在演算法導論上看到過,然而已經忘了。。。想了想,如果說每次劃分正好在陣列的正中間,那麼可達一個較優的情況所以就答了中位數) 面試官:那再問問其他問題,有了解過其他最差情況不會像快排這樣的排序演算法嗎? 答:(這裡感覺面試官問的應該是穩定的排序演算法有哪些,當時能想起來的就是歸併排序結果一不小心答成分治排序 - -) 補充:從別的地方拿來的圖 ![](https://img2020.cnblogs.com/blog/1413964/202005/1413964-20200529181442417-1824026807.png) ## 演算法題 寫了道連結串列翻轉,結果很尷尬,忘了將翻轉後的連結串列最後一個元素的 next 設定為空,導致一直超時 orz 。。。。。過程中邊 debug 邊跟面試官討論,最後改出來了。。害,太久沒手寫過資料結構了,這麼一道簡單的題還寫出 bug。。。哭了 ## 提問 問了下想到網易做遊戲開發需要學些什麼(畢竟當年是想做遊戲開發才選的計算機,而且大一剛入學的目標就是網易遊戲,雖然後來搞了近兩年機器學習。。),面試官說是並沒有太指望應屆生有遊戲開發相關的知識,要求就是基礎要紮實,能夠做到他們交給我們的東西我們能學會。(不說了,接著補基礎去了。。。) # 小節 一次體驗極好的面試,總共面了一個小時多一點,過程中有答不上來的地方面試官會慢慢引導自己,結束之後感覺好像答的還不錯,梳理一下發現問題還是有點多 orz。。面試之前看了不少網易遊戲研發的面經,照著面經準備了幾天,發現被問到的面經上都沒出現,真就全靠平時積累。。。看來還有好多地方需要補一補。。說是一週內會出結果,只能看命了。。 從三月份開始投演算法崗,一直到之前改投開發崗,掛了無數次,看著周圍一些同學都拿了不少 offer,壓力有點大。。 ![](https://img2020.cnblogs.com/blog/1413964/202005/1413964-20200529174906654-2044930818.png) ![](https://img2020.cnblogs.com/blog/1413964/202005/1413964-20200529174601060-1005227671.jpg)