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


前言

昨天面了網易互娛的游戲研發工程師,回想下似乎問的問題並不多,整體也就 5 個問題,但每個問題展開之后里面的量好像也不少,現在整理一下,順便解決下面試中沒答上來的地方。

面試題

先是自我介紹。。。。。面試官了解到我對 Python 更加熟悉一些,於是問了比較多的 Python 相關的問題。

Python 中如何實現類成員的 public、private、protected

面試官:在 C++、Java中,定義一個類,其成員可以申明為 public、private、protected, 那么在Python 中如何實現類成員的 public、private、protected
答:Python 語言並不存在控制訪問,所以無法直接定義類成員的 pubilc、private等屬性,一般情況下是通過命名規約來達到這個效果,對於 private 的成員,一般命名以 _ 開頭,而 public 的則正常命名即可。

面試官:那對於雙下划線__開頭的成員呢?

答:雙下划線開頭的成員感覺主要是用在類的繼承的時候,如果不想子類直接訪問到父類的這個成員,則可以以雙下滑線開頭。(修正,不僅僅是繼承的時候,在該類中定義了雙下划線開頭的成員,實例化的對象也無法直接訪問該成員)

面試官:如果我訪問了這個雙下划線開頭的成員,會報什么錯誤?

這里我突然就愣住了,因為之前都沒去嘗試過,愣了一會兒之后,面試官給了些提示,如果你訪問一個變量,但這個變量沒有定義的話,那會報什么錯誤?

答:應該是變量不存在吧

面試官:那上面那個問題是報什么錯誤呢?

答:這么一說感覺應該是變量不存在

面試官:那再問問如果我非要訪問這個雙下滑線開頭的成員,要怎么做?

這里真就不會了 orz

現在來補一下

'''
@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)

運行一下

那我該如何訪問它呢?查了下資料,發現雙下划線開頭的成員,會被重命名,變成 _類名 + 成員名,在這里就是b._base__private

print(b.public)
print(b._internal)
print(b._base__private)

函數也是類似

python 修飾器

面試官:了解過修飾器嗎?

答:了解過

面試官:介紹下 Python 中修飾器(問題大概就是這個意思吧)

答:balabalabala。。。。(大致意思就是減少代碼重復,封裝成裝飾器方便使用,類似於函數)

面試官:那一個裝飾器的輸入和輸出是什么呢?

答:輸入?可以是任意的參數吧,這個不是根據實際定義的嗎?(這里我理解錯了面試官的意思了- - ,因為之前在做 web 后端的時候,用了修飾器來做 token 驗證,當時將 token 作為一個參數使用了)后面在面試官的引導下,反應過來了,輸入和輸出都是函數。

面試官:如果我不采用 @修飾器名稱 的方式來調用修飾器,那該怎么做?

答:我印象中是直接當做函數調用就好了,但是好像並沒成功 orz 。。

先來個一般寫法

def foo(f):
    def inner():
        print('inner')
        return f
    return inner

@foo
def bar():
    pass

bar()

會發現輸出了 inner,然后我當時寫了這樣的調用

def foo(f):
    def inner():
        print('inner')
        return f
    return inner

def bar():
    pass

foo(bar)

發現沒輸出 orz, 然后就過去了,后來仔細想想,雖說返回的是函數,但只是這個函數名啊,我並沒有調用它哪來的輸出啊,菜哭。。

改成這樣就好了

bar = foo(bar)
bar()
# 或
foo(bar)()

python 迭代器

面試官:了解過迭代器嗎?可以介紹下嗎?

答:迭代器一般是用在對 Python 中的數據結構進行遍歷,比如我現在有一個名為 li 的 List,我想對里面每個元素進行修改,那就需要遍歷每個元素,這時通過 for number in li: 這條語句,便會生成一個迭代器,然后 number 為當前所在位置的元素。

面試官:那這跟直接索引遍歷相比的好處是什么?

答:(這里憑感覺答的,也不清楚對不對)1. 按索引遍歷的話首先需要知道這個數據結構的長度。2. 每次遍歷的時候都需要通過索引來獲取這個數據,而通過迭代器可直接獲取到數據。

面試官:那有沒有什么情況下是不能使用迭代器的呢?

答:這里我覺得存在刪除操作的時候應該是不能使用迭代器的,如下面這段代碼, 我想刪除列表中大於 3 的元素

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。。。。

面試官:那來算一下這個結構體的大小吧

struct Node
{
    short a;
    long b;
    char c;
    char d;
    int e;
    int f;
    short i;
    short j;
    long k;
};

答:(算就算吧),算了一會兒,算出來一個 34 字節

面試官:怎么得出來的

答:首先 short 占 2 字節, 然后 long 占 8 字節, 后面加起來總共是 22 字節,對齊一下就是 24 字節,加起來總共 34 字節。(后來驗證了下,發現自己錯了 orz)

面試官:你確定這里第一個 short 只占 2 字節嗎?

答:balabalabala。。。(我還覺得自己很對,后來下來驗證了下發現自己打錯了 orz)

面試官:這里操作系統是怎么讀取數據的?一次能讀兩個字節嗎?

答:(這里我已經懵逼了)emmmmm。。。不太清楚。。我記得這里應該是讀取一個起始位置 + 偏移量來獲取這個數據。

面試官:下去之后有興趣再去了解了解吧

這里開始補充,發現 mingw64 long只占 4 個字節???

/*
 * @Description: 
 * @Author: 妄想
 * @Date: 2020-05-29 16:42:59
 * @LastEditTime: 2020-05-29 16:54:49
 * @LastEditors: 妄想
 */ 
#include<iostream>
#include<stdio.h>
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;
}

看一下輸出

這個 long 只占 4 字節有點迷,沒辦法,就先改成 long long 吧。

可以發現,變量 b 的起始位置是 8 而不是 2,e 的起始位置是 20 而不是 18。

查了下相關博客

  1. 結構體中元素需被放置在自身對齊大小的整數倍的位置上
  2. 如果結構體的大小不是所有元素中最大對齊大小的整數倍,則結構體對齊到最大元素對齊大小的整數倍,填充空間放置到結構體末尾

排序算法

面試官:接下來問問算法方面的東西吧,說一說快排的流程。

答:(很尷尬。。。已經很久沒有接觸過排序算法了,近期准備面試也沒看過排序方面的東西,所以想了一段時間,好歹還是想起來了) balabalabala。。。。

面試官:那時間復雜度呢?

答:最差 \(O(n^2)\) ,平均 \(O(n\log n)\)

面試官:什么情況下最差呢?

答:數組完全逆序排序的時候

面試官:那怎么選取主元能使得快排的性能最好呢?

答:(這個之前在算法導論上看到過,然而已經忘了。。。想了想,如果說每次划分正好在數組的正中間,那么可達一個較優的情況所以就答了中位數)

面試官:那再問問其他問題,有了解過其他最差情況不會像快排這樣的排序算法嗎?

答:(這里感覺面試官問的應該是穩定的排序算法有哪些,當時能想起來的就是歸並排序結果一不小心答成分治排序 - -)

補充:從別的地方拿來的圖

算法題

寫了道鏈表翻轉,結果很尷尬,忘了將翻轉后的鏈表最后一個元素的 next 設置為空,導致一直超時 orz 。。。。。過程中邊 debug 邊跟面試官討論,最后改出來了。。害,太久沒手寫過數據結構了,這么一道簡單的題還寫出 bug。。。哭了

提問

問了下想到網易做游戲開發需要學些什么(畢竟當年是想做游戲開發才選的計算機,而且大一剛入學的目標就是網易游戲,雖然后來搞了近兩年機器學習。。),面試官說是並沒有太指望應屆生有游戲開發相關的知識,要求就是基礎要扎實,能夠做到他們交給我們的東西我們能學會。(不說了,接着補基礎去了。。。)

小節

一次體驗極好的面試,總共面了一個小時多一點,過程中有答不上來的地方面試官會慢慢引導自己,結束之后感覺好像答的還不錯,梳理一下發現問題還是有點多 orz。。面試之前看了不少網易游戲研發的面經,照着面經准備了幾天,發現被問到的面經上都沒出現,真就全靠平時積累。。。看來還有好多地方需要補一補。。說是一周內會出結果,只能看命了。。

從三月份開始投算法崗,一直到之前改投開發崗,掛了無數次,看着周圍一些同學都拿了不少 offer,壓力有點大。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM