2016屆360公司PHP服務端開發筆試和麵試之所得所感
第一部分:360公司筆試題
第二部分:面試過程
第三部分:注意事項及心得體會
同時,真心感謝360公司,我非常向往的一個公司。也非常感謝給我面試的那位大哥,讓我真的學到了很多東西。所有題目版權歸360所有,如果有不適的地方請告知我刪除或修改。總之我認為:有的時候瞭解別人失敗的案例比你總看別人成功的例子對你的幫助更大。看了下面我的本科畢設,你就會知道為什麼我這麼推崇這個公司了。
一. 筆試題目
面試時間:2015年9月16日
面試崗位:PHP服務端開發工程師
職位要求:精通PHP/Python語言語法、掌握MySQL,基本瞭解Redis和MongoDB等各種DB、掌握HTML/CSS等。
題目難度:較難,選擇題考得比較廣,程式設計題一道極為簡單一道比較複雜。
PS:因為當時題目都是一邊做一邊在草稿紙上抄的,可能有遺漏的地方,請海涵~
(一) 單選題:
1.MySQL儲存過程的優點:
某選項可以多次呼叫、修改,網路負載降低
2.找出/etc/my.conf檔案屬於哪個包(package),執行:
A.rpm -qf /etc/my.conf B.rpm -q /etc/my.conf
C.rpm -q | grep /etc/my.conf D.rpm -requires etc/my.conf
題解: 該題考察linux,答案是A。其中-f Query package owning FILE,賽馬網:
-ivh:安裝顯示安裝進度--install--verbose--hash
-Uvh:升級軟體包--Update;
-qpl:列出RPM軟體包內的檔案資訊[Query Package list];
-qpi:列出RPM軟體包的描述資訊[Query Package install package(s)];
-qf:查詢指定檔案屬於哪個RPM軟體包[Query File];
-Va:校驗所有的RPM軟體包,查詢丟失的檔案[View Lost];
-e:刪除包
3.下面程式碼的執行結果:
A.1 B.警告,沒定義a::$myvar
C.2 D.一個錯誤,沒定義a::$myvar
<?php
class a{
function a($x=1) {
$this->myvar=$x;
}
}
class b extends a{
var $myvar;
function b($x=2) {
$this->myvar=$x;
parent::a();
}
}
$obj=new b;
echo $obj->myvar;
?>
題解:答案A. 參考4.以下程式碼能正確顯示圖片的是:
PS: 由於4段程式碼,僅僅手抄了B答案,僅供參考
<?php
header("content-type:image/jpeg");
$img=imagecreatefromjpeg("images/scce.jpg").imagejpeg($img);
imagedestroy($img);
?>
5.下面的指令碼輸出值為多少:
A.5 B.2 C.10 D.NULL
<?php
class my_class{
var $value;
}
$a=new my_class;
$a->my_value=5;
$b=$a;
$b->my_value=10;
echo $a->my_value;
?>
題解:通過 http://www.mcqyy.com/RunCode/php/ 執行結果為C.10$b=$a的賦值,僅僅是建立一個連結,賦值後對$b的修改會影響$a。
6.Person類例項化(new)一個物件$p,那使用物件$p呼叫Person類中getInfo方法:
A.$p->getInfo() B.this->getInfo()
C.$p::getInfo() D.$p=>getInfo()
題解:A,常用的考察PHP類定義呼叫方法的問題。
7.下列關於工廠方法factory敘述正確的是那個:
8.R=(A,B,C)與SQL語句select distinct A from R where B=17等價關係代數表示式:
A.πA(σB=17(R)) B.σB=17(πA(R))
C.σB=17(πA,C(R)) D.πA,C(σB=17(R))
題解:其中select語句對應σB=17(R),而Select distinct A為消除重複,答案為A.
投影操作π是一個關係操作,所謂的出現重複行是指多個記錄在投影屬性上具有相同的取值,例如參考百度百科:
學號 姓名 性別 年齡
01 艾倫 男 17
02 三笠 女 17
03 阿明 男 17
在性別和年齡兩個屬性上投影后資料集只保留這兩個屬性列,結果如下:
性別 年齡
男 17
女 17
男 17
其中第一行和第三行就是重複行,雖然來自不同記錄,但是這兩個屬性上的內容相同。需要消除相同的行(SQL語句預設不消除重複),最後結果就是:
性別 年齡
男 17
女 17
9.計算機cache,一主存層次採用相聯對映方式,塊大小為128位元組,cache容量64塊,按4塊分組,主存容量為4096塊,主存地址共需______位。
題解:由於主存容量為4096塊,而每塊為128個字,主存的總容量為512K字,故主存地址應為19位。主存地址應分為區號、組號、組內塊號、塊內地址號。可以看到,塊內地址號應為7位,用以表示128個字。一組為4塊,則組內塊號用2位表示。Cache容量為64塊共分16組,故組號需要用4位地址表示。剩餘的即為區號,主存區號應為6位。|
10.下列程式碼的運算結果為多少:
var a = new Array(2,3,4,5,6);
var sum=0;
for(i=1;i<a.length;i++)
sum+=a[i];
document.write(sum)
題解:計算3+4+5+6=18
11.document物件的是:
A.form B.link C.三項都是 D.anchor
答案:C
12.mysql資料庫還原命令是:
題解:恢復、備份資料庫備份資料庫shell > mysqldump -h host -u root -p
13.求下列程式碼的時間複雜度,more than one answer is correct, choose the smallest one ( ).
for(i=0; i<n; i++)
for(j=1; j<=m; j*=2)
for(z=j/2; z<j; z++)
其中某項答案:O(n*log(m)*m)
14.HTML5庫拋棄了:
A.form B.applet C.frame D.center
題解:html5不再使用fram,答案C。不再用frame、noframes和frameset,這些標籤對可用性產生負面影響。HTML5中不支援frame框架,只支援iframe框架,或者用伺服器方建立的由多個頁面組成的符合頁面的形式,刪除以上這三個標籤。
15.HTML5中,input元素type屬性預設值為:
A.search B.hidden C.text D.form
題解:預設應該是text
16.下列程式碼的輸出結果是:
A.24 B.17 C.72 D.36
d=lambda p:p*2
t=lambda p:p*3
x=2
x=d(x)
x=t(x)
x=d(x)
print x
題解:感覺lambda表示式替換 2*2=4 4*3=12 12*2=24,應該輸出A。Right?17.不是動態規劃演算法基本要素的是:
A.馬爾可夫性 B.建表填 C.運用子項疊代 D.最優子結構
答案:A
18.不要求最優子結構的是:
A.分治法 B.貪心 C.動態規劃 D.回溯
答案:D
19.下列敘述正確的是:
PS:太長記不下來了
20.設有N堆沙子排成一排,其編號為1,2,3,…,N(N<=100)。每堆沙子有一定的數量。現要將N堆沙子併成為一堆。歸併的過程只能每次將相鄰的兩堆沙子堆成一堆,這樣經過N-1次歸併後成為一堆。找出一種合理的歸併方法,使總的代價最小:
PS:答案沒記錄下來,但是這是典型的動態規劃問題。
參考:http://blog.csdn.net/abcjennifer/article/details/5805330
21.下列不是分治法所能解決的問題特徵是:
A.子問題的解無後效性
題解:只能懷疑答案是A,因為其它選項忘了,請見諒!分治法通常分為"分解-解決-合併"三個步驟,其中若干小規模的問題是可以解決的子問題,即具有最優子結構性質;最後將各個子問題的解合併為原問題的解。
22.<div><a href="http://www.360.com">360</a></div>紅色連結不正確的是:
A.a:link{color:red}
題解:該題考察網頁基礎知識,包括CSS定義超連結顏色等。A答案肯定正確,比較考察實際應用。
23.下列不屬於結構性偽類的是:
A.E:root B.E:enabled C.E:first-child D.E:empty
24.TCP連線,socket呼叫recv函式返回值為0表示:
A.對端傳送了一段長度為0的資料
B.對端關閉了連線
C.還沒有收到對端資料
D.連線發生錯誤
題解:答案B。如果recv函式在等待協議接收資料時網路中斷了,那麼它返回0。預設 socket 是阻塞的。阻塞與非阻塞recv返回值沒有區分,都是:
<0 出錯 =0 連線關閉 >0 接收到資料大小。
25.需對檔案進行隨機存取,下列哪種檔案物理結構不適合上述應用場景?
A.順序檔案 B.索引檔案 C.連結檔案 D.Hash檔案
題解:答案C。鏈式儲存結構的儲存地址不一定連續,無法通過計算地址實現隨機訪問,只能順序訪問。如果要隨機訪問的話只能順序查詢,效率低下。
26.關於int *const ptr敘述正確的是:
A.ptr不可修改,*ptr可修改
B.ptr可以修改,*ptr可修改
C.ptr可以修改,*ptr不可修改
D.ptr不以修改,*ptr不可修改
題解:答案A。參考牛客網。const 的作用就是封鎖它後面的東西,即後面的不可改變。
對於 int *const ptr 沒有const關鍵字時為int* ptr,此時ptr是指向int的指標。加上const後,const修飾並封鎖ptr ,即ptr的指向不可改變。
同理 int const* ptr(等同 const int *ptr) 。const修飾 * 解引用,即指標指向的內容不可改變。
27.下列錯誤的用法是:
PS:其中某個答案為 D.typedef void (*FUN)()
28.下面程式碼fun(21)輸出值多少:
int fun(int a) {
a^=(1<<5)-1;
return a;
}
題解:首先(1<<5)表示左移5位,相當於1乘以2的5次方,即100000=32。
然後是異或運算:
21=010101 ^ 31=011111 =》 001010=10,結果為10。
29.sort的template正確的寫法是:
A.void sort(class A first,class A last,class B pred)
B.void template(class A,class B)sort(A first,A last,B pred)
C.template<class A><class B> void sort(A first,A last,B pred)
D.template<class A,class B> void sort(A first,A last,B pred)
題解:參考牛客網,答案D。
函式模板的宣告
模板函式格式是先宣告模板型別,然後才能使用。 函式模板可以用來建立一個通用的函式,以支援多種不同的形參,避免過載函式的函式體重複設計。它的最大特點是把函式使用的資料型別作為引數。
函式模板的宣告形式為:
template<typename 資料型別引數識別符號>
<返回型別><函式名>(引數表)
{
函式體
}
格式 template<class T1, class T2, ...> 返回值 函式名(引數列表){//函式體}
30.16位機器,浪費多少空間?
struct {
char a;
int b;
char a;
}
A.8 B.4 C.6 D.2
題解:答案D。16位機器,char型佔1位元組,int型佔2個位元組。資料自動對齊,實際結構體:1(char)+1(補齊)+2(int)+1(char)+1(補齊)=6位元組,浪費2個位元組空間。
參考我的部落格:[C/C++基礎知識] 面試再談struct和union大小問題
31.一道關於A[m][n]陣列處理的題目:
PS:答案好像有644、676、696等。
32.關於C/C++巨集定義錯誤的敘述是:
A.巨集定義不檢查引數正確性,會有安全隱患
B.巨集定義的常量更容易理解,如果可以使用巨集定義常量的話,要避免使用const常量
C.巨集的巢狀定義過多會影響程式的可讀性,而且很容易出錯
D.相對於函式呼叫,巨集定義可以提高程式的執行效率
題解:參考牛客網,答案B。參考:http://bbs.csdn.net/topics/340089467
使用const比使用define有一下幾種好處:
(1)const會進行資料型別檢查,而define不會
(2)const儲存在符號表\常量區,表示值不能修改
33.下列值為多少:1^2^....^100
題解:答案100,python程式碼如下圖所示:
34.下列關於繼承錯誤的是:
A.只能公有繼承,不能私有繼承
B.派生類可以訪問基類protect成員
C.一個基類可以繼承多個派生類,一個派生類可繼承多個基類
D.基類中至少有一個虛擬函式可構成多型
35.下列程式碼的輸出值為多少:
int main(int argc, char **argv)
{
int a[4] = {1, 2, 3, 4};
int *ptr = (int *)(&a + 1);
printf("%d", *(ptr - 1));
}
A.3 B.1 C.2 D.4
題解:答案D。參考賽馬網:
考察對於陣列和指標的認識,指標加一的能力由型別決定。int*ptr=(int*)(&a+1); &a 和a 都指的是陣列首元素的地址。不同的是a就是a+0 ,*(a+0)就是a[0],而&a+1相當於a[]陣列型別的指標加1,此時指標加到陣列的末尾。ptr接受後,由於Ptr的型別是int* 因此ptr-1即回退4位元組。即指到最後一個元素。
A.static_cast
B.dynamic_cast
C.const_cast
D.reinterpret_cast
題解:答案B。
dynamic_cast:在基類和派生類之間的轉換,繼承體系安全向下轉型或跨系轉型,找出某物件佔用記憶體的起始點。static_cast:同舊式C轉型,如int 到double。const_cast:常用於去除某個物件的常量性。reinterpret_cast
不具備移植性,常見用途是轉化函式指標型別。
37.下列是獲得例項化物件所屬類名字的函式是:
A.get_class_methods()
B.get_class()
C.get_classname()
D.get_object_vars()
題解:答案B。PHP中沒有get_classname()函式,其他如下:
get_class — Returns the name of the class of an object
get_object_vars — Gets the properties of the given object
get_class_methods — Gets the class methods' names
(二) 程式設計題:
1.計算器的新功能
視覺化程式設計一個新功能的計算器,輸入一個數時,能將這個數分解為一個或多個素因子乘積的形式,並按素因子的大小排列顯示出來,0-9這十個數字表示如下:每個數字佔5*3大小的字元區域。
輸入:多組測試數n(n<=1,000,000)
輸出:每個數分成若干個素數乘積形式,從小到大輸出。素因子之間用"*"形式連線。
例:
輸入:
10
2
輸出:
- -
| |
- * -
| |
- -
-
|
-
|
-
2.研究生考試
政治100分,英語100分,數學150分,專業課150分。政治、英語要求單科不低於60分,數學、專業課要求單科不低於90分,總分不低於310分。總分350以上(含350)為公費,310-349分為自費。
請程式設計判斷考生情況。
輸入:正整數N,表示N組測試資料。每組4個正整數分:政治、英語、數學、專業
輸出:Fail/Zifei/Gongfei
例:
3
61 62 100 120
80 80 120 100
55 90 130 130
輸出:
Zifei
Gongfei
Fail
PS:該題目比較簡單,基本為送分題。同時希望該部分題目對你有所幫助!再次宣告,此部分為我一邊做題一邊抄在紙上,所以有些遺漏的地方,請原諒~
二. 面試過程
面試時間:2015年10月9日
面試部門:伺服器端開發
面試地點:360大廈
面試時長:100多分鐘
PS:過程中可能存在一些遺漏的地方,但是還是非常感謝那個面試的哥哥,今天都還覺得給人很舒服的感覺。同時因為間隔時間太長,最近也太忙,不準備採用對話方式進行,而是分幾個步驟進行簡單敘述。
第一部分 自我介紹
1.首先簡單問候面試官並遞上自己的簡歷,然後做個自我介紹;
2.面試官通過我的簡歷,讓我介紹自己最拿得出手的專案,我介紹的是知識圖譜相關的專案,包括:傳統搜尋引擎的工作原理、知識圖譜概念(舉例姚明身高、梁啟超關係查詢)、實體消歧與實體對齊、採用的VSM向量模型及聚類演算法;
3.面試官問我該階段主要熟悉什麼語言?我說現在做得最多的是Python,以前是C/C++,當然Java、C#、PHP都做過,畢竟語言都有通性,但是想精通還是難。
4.他說PHP比較簡單,他們是做底層伺服器方向的,今天的面試主要是問Unix相關知識;我也贊同這個觀點,因為PHP可以通過一些開源框架實現,同時也問了些自己做的WAMP網站。
第二部分 Unix為主
1.面試官首先問我是否做過Unix相關的東西?我說自己就簡單做過Linux下的Python爬蟲、指令碼等。
2.然後問了Unix下的網路程式設計會不會?我簡單介紹了Python的網路程式設計TCP\UDP的過程,主要的三次過程如下,同時Socket其他語言過程基本類似。
伺服器:
ss = socket() # 建立伺服器套接字
ss.bind() # 地址繫結到套接字上
ss.listen() # 監聽連線
inf_loop: # 伺服器無限迴圈
cs = ss.accept() # 接受客戶端連線 阻塞式:程式連線之前處於掛起狀態
comm_loop: # 通訊迴圈
cs.recv()/cs.send() # 對話 接受與傳送資料
cs.close() # 關閉客戶端套接字
ss.close() # 關閉伺服器套接字 (可選)
客戶端:
cs = socket() # 建立客戶端套接字
cs.connect() # 嘗試連線伺服器
comm_loop: # 通訊迴圈
cs.send()/cs.recv() # 對話 傳送接受資料
cs.close() # 關閉客戶端套接字
3.然後他又問如果客戶端出現異常,伺服器怎樣捕獲這個異常呢?我當時想了下,提出了伺服器可以設定一個時間點(心跳),當某段時間沒有接受到該客戶端的報文,則表示斷開連線或異常錯誤。他又問我能不能把這段recv()函式寫出來。我說不太會。
PS:回來後想了想,當時是不是在考察recv()函式的返回值: >0獲得報文長度, =0客戶端斷開連線,<0連線發生異常錯誤。但確實自己也不會Unix下的網路程式設計。
4.面試官又問了些Unix下的fork相關的知識,我說沒有接觸過。還有些英文不知道是什麼,自己英語太差了~
第三部分 演算法和資料結構
1.面試官說:“你資料結構和演算法應該很熟悉了吧!”我說:“還行,但是也忘記很多了。”自己確實很多基礎知識都忘了很多,擔心回答不上來。
2.面試官給我一張紙,有兩段很長的程式碼(C語言),讓我尋找兩程式碼的區別。
這兩段程式碼的主要區別就是引數一個是int,一個是double,當然前面還定義了些結構,程式碼裡面的內容基本類似,相當於一個int型排序,一個double型排序。
他問我平時肯定會遇到這種情況,寫兩個函式程式碼過於冗餘,怎樣提煉成實現兩種不同的型別排序,而且型別可以是float、結構體等等。
我說這有點類似於C++的模板啊!如果是C++就簡單了,但是C語言主要是怎樣判斷這個型別呢?
PS:後來回來想了想,感覺類似於qsort快速排序的那種寫法,通過const void *a實現,不知道是不是。但有同學懷疑是不是考察##的連線用法。
int型快排
int cmp1(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
qsort(num, len, sizeof(int), cmp1);
double型快排
int cmp(const void *a, const void *b)
{
return *(double*)a > *(double*)b ? 1 : -1;
}
qsort(num, sum, sizeof(double), cmp);
char型快排
int cmp(const void *a, const void *b)
{
return *(char*)a - *(char*)b;
}
qsort(str, sum, sizeof(char)*10, cmp);
3.上面程式碼沒有寫出來,那麼你就做個最簡單的吧!二叉樹中序遍歷非遞迴實現。
他又問我以前是怎麼做的?我說通常都是三句話遞迴,這個題主要是考察通過棧模擬二叉樹遍歷遞迴的過程,然後寫程式碼中。我失誤了,棧寫成隊列了,然後佇列是先進先出,又通過兩個佇列(一個輸入佇列、一個輸出佇列)模擬了一個棧實現了非遞迴遍歷。
中序遍歷:左孩子-根節點-右孩子,總體程式碼如下。參考
遞迴程式碼
void inOrder1(BinTree *root) //遞迴中序遍歷
{
if(root!=NULL)
{
inOrder1(root->lchild);
cout<<root->data<<" ";
inOrder1(root->rchild);
}
}
非遞迴遍歷
根據中序遍歷的順序,對於任一結點,優先訪問其左孩子,而左孩子結點又可以看做一根結點,然後繼續訪問其左孩子結點,直到遇到左孩子結點為空的結點才進行訪問,然後按相同的規則訪問其右子樹。因此其處理過程如下:
對於任一結點P,
1)若其左孩子不為空,則將P入棧並將P的左孩子置為當前的P,然後對當前結點P再進行相同的處理;
2)若其左孩子為空,則取棧頂元素並進行出棧操作,訪問該棧頂結點,然後將當前的P置為棧頂結點的右孩子;
3)直到P為NULL並且棧為空則遍歷結束
void inOrder2(BinTree *root) //非遞迴中序遍歷
{
stack<BinTree*> s;
BinTree *p=root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
s.push(p);
p=p->lchild;
}
if(!s.empty())
{
p=s.top();
cout<<p->data<<" ";
s.pop();
p=p->rchild;
}
}
}
如下圖所示:第四部分 結束面試
1.面試官問我最近在看什麼書?我說《Python核心程式設計》和《Web資料探勘》,然後問我有沒有看過Unix的書籍,我說看過《Unix程式設計藝術》前兩章。他就給我推薦了三本書,希望我回去看這三本,其他可以放一邊了,那些都是小兒科了。
《Unix高階環境程式設計》《TCP\IP協議》《Unix網路程式設計》
PS:這三本數都是Unxi傳奇W.Richard Stevens的作品,當時以為推薦書,有面試了100分鐘以為有戲。可惜了,哈哈~
2.然後又問我有什麼問題,我說想自己實現個小的搜尋引擎系統;他給我分析了硬體裝置、分詞、索引、倒排序、Rank、推薦系統等等知識。
3.最後讓我出去等了大概15分鐘左右,好像他們那天也比較忙,最後還是方向不太對口被拒了。但我自己已經非常知足了,一方面從他那學到了很多,另一方面也深深認識到了自己的不足,當初隨便報了個PHP方向居然能面試,我也不知道報了這個方向。
三. 注意事項及心得體會
在最後總結之間,說點題外話。在回學校之前,因為360公司就在798藝術工廠的旁邊,我去到那裡逛了3個多小時。寫下這樣一段話:
“今天早上來360面試,估計已跪,但仍不虛此行。會不會程式設計我不知道,但去了它旁邊的798,發現自己還是有藝術細菌的。
好喜歡這種什麼也不想,什麼也不做,就靜靜地坐在角落,看著川流不息的人行的感覺。是那樣的踏實愜意,那樣的無憂無慮~
因為不喜旅遊,否則再忙也要出去看看這大千世界。但有時候又覺得做個井底之蛙也沒有什麼不好的,至少還可以每天看月亮。”
——Eastmount
最後簡單總結下:
面試中經常考察的問題包括:
1.Socket套接字通訊,TCP\UDP、同步非同步解決方法;
2.基本演算法和資料結構題目,包括二叉樹遍歷(含非遞迴)、快速排序(手寫程式碼)、連結串列翻轉等;
3.程序與執行緒的區別,是否寫過執行緒相關的,如何解決同步、互斥等問題;
4.設計模式,如代理模式(圖片瀏覽縮圖)、工廠模式、觀察者模型等;
5.Cookie和Session的區別,快取內容等,Android、前端開發常問;
6.後端開發常常會問Unix\Linux+C語言+網路通訊的知識;
7.Python還會問爬蟲、正則表達、開源框架Spider、docker、執行緒通訊等;
8.自然語言處理會問分詞、分類聚類、搜尋引擎、推薦系統等;
提供幾點建議:
1.申請職位一定要慎重考慮,一定是自己熟悉的東西,而不是各種職位都申請;
2.簡歷上的專案自己一定要熟悉,能說出專案的內容;
3.如果現在距離找工作早,建議嘗試學習Linux、Unix下程式設計;
4.網路通訊常常會問,簡單的是TCP\UDP\Socket程式設計問題,三次握手等,如果深入就需要Unix相關知識;
5.演算法很重要,如果有時間,一定要去做LeetCode題目,因為真的很多很多公司筆試面試題目都來自這裡,比如連結串列翻轉、字串相似判斷、二叉樹遍歷非遞迴等等;
6.如果有可能,儘量做些有深度的專案,簡歷中寫"熟悉XXX語言、熟悉HTML或MySQL資料庫",顯然不如"對Linux下網路程式設計比較熟悉,通過Spider或XX框架進行過分散式爬取"。儘量讓自己的簡歷更加專業、有水平。
7.如果有開源專案或者研究過原始碼、驅動這些最好不過,但顯然很少人做到。
最後希望文章對你有所幫助,如果有不足或錯誤的地方,還請海涵~希望大家都找到自己心儀的工作。
作者寫這篇文章也不容易,最近真心太忙了,明天還有好幾個筆試面試,自己也報了幾個貴州的大學,還是想回去任教啊!一生的夢想,不知在何方;但是不論深處何地,做什麼工作,都需要不斷地學習,保持一顆平常心和健康的身體去生活。哈哈,加油~
(By:Eastmount 2015-10-17 深夜2點半 http://blog.csdn.net/eastmount/)