面試崗位
后端開發(fā)
一面 (2021.0816)
臨陣抱佛腳準(zhǔn)備了一下八股,結(jié)果就問了三個算法題。
算法題
- 加密,給一個映射表,讓把文本加密成密文
答:簡單映射
兩個字符串,找到最長公共字符串。
答:的做
-
給一個
Unix
風(fēng)格路徑如/home/app/../a/./..
,做簡化
答:原題是這個《71.簡化路徑》,思路是搞一個棧然后每次push進去- 3 這里擴展問了幾個問題:
如果加入一個
throw
,在異常時拋出,需要在哪些地方加?
答:① 已經(jīng)到達(dá)根目錄,還要通過..
回退到上一目錄時
② 出現(xiàn)非法字符時
③ 字符串開頭不為/
或字符串為空時兩個斜杠表示什么
//
答:和一個斜杠/
一個意思由于我一開始實現(xiàn)時,最后合并結(jié)果是循環(huán)執(zhí)行
ans = s.top() + ans;
所以他問我這一步可以優(yōu)化嗎
答:可以優(yōu)化,兩種形式,一種是再搞一個棧/數(shù)組,把整個棧中的元素都反轉(zhuǎn)一下,然后用ans += s.top()
,還有一種辦法就是ans += 反轉(zhuǎn)的s.top()
,最后再做一次反轉(zhuǎn)。并解釋自己是圖省事兒沒有做這步優(yōu)化,(自己其實知道)每次在stirng頭部加內(nèi)容性能很慢。追問:如果有
個字符串,每個字符串長度都是
,通過頭部累加的形式合并成一串,那么復(fù)雜度是多少?
答:每次拼接時都會把以拼接部分拼接到新的字符后面,整個過程是的。
- 3 這里擴展問了幾個問題:
一面 (2021.0820)
可能是該部門那個組沒有名額了,把我推薦給了同部門另一個組重新面試。這次面試時間是晚上 點,能看出來小哥是真的渴望下班
基礎(chǔ)題
如果有一個很大的數(shù)據(jù)流,想知道里面
top-k
的最大值,該怎么辦?
答:搞一個大小為的堆
堆排序的一次查找過程時間復(fù)雜度多少?
答:堆排序時間復(fù)雜度多少,怎么算的?
答:,遍歷是
,建堆/調(diào)整堆都是
有其他
復(fù)雜度的排序算法嗎,他們分別是怎么算的?
答:歸并:每次合并是的,二分過程是
的
快排:每次按照基礎(chǔ)元素排序是的,二分是
的
內(nèi)核態(tài)和用戶態(tài)了解嗎,是什么?
答:為了減少有限資源的訪問和使用沖突,對不同的操作賦予不同的執(zhí)行等級,就是所謂特權(quán)的概念。簡單說就是有多大能力做多大的事,與系統(tǒng)相關(guān)的一些特別關(guān)鍵的操作必須由最高特權(quán)的程序來完成。Linux操作系統(tǒng)中主要采用了0和3兩個特權(quán)級,分別對應(yīng)的就是內(nèi)核態(tài)和用戶態(tài)。內(nèi)核態(tài)切換到用戶態(tài)的情況通常有系統(tǒng)調(diào)用、中斷、和外圍設(shè)備異常。線程和進程區(qū)別?
答:……(此處太長省略)進程間通信方式有哪些?
答:PIPE、有名管道、消息隊列、信號量、信號、共享內(nèi)存、套接字。長連接短連接知道嗎?
算法題
- 最長上升子序列
答:維護一個長度為的數(shù)組
二面(2021.0824)
又臨陣抱佛腳了一下八股,結(jié)果還是沒問
基礎(chǔ)題
說要實現(xiàn)一個發(fā)紅包的算法怎么實現(xiàn),比如
個人,
元錢。
答:可以搞一個范圍的隨機數(shù),然后每次從當(dāng)前所有錢中計算拿到多少,剩下的繼續(xù)下一輪,最后一個人拿走所有。(但這一步我不會證明是否是公平的)
-
如果春節(jié)期間,好多人都在搶紅包發(fā)紅包怎么辦?
答:降級、削峰、限流。- 降級指的是服務(wù)降級,這里指的是通過沒那么高級的服務(wù),來緩解瞬時壓力。比方說可以不用上面的隨機數(shù),預(yù)先計算幾千組隨機序列,發(fā)紅包時直接去套已有的隨機序列模板,減少隨機數(shù)生成計算等過程;更進一步的,可以把如
這種吉利數(shù)字作為紅包隨機值,增加用戶體驗,試想誰大年三十搶到一個吉利數(shù)紅包不開心呢。
- 削峰指的是把瞬時流量拉長,比如增加紅包動畫,或者增加復(fù)核操作等,讓用戶盡可能錯峰的完成發(fā)紅包搶紅包這個過程。
- 限流是為了保護后臺服務(wù)器不被沖爆,可以搞一個消息隊列,把所有的請求放進去,按照服務(wù)器水平來取用。甚至可以提前做好備案,根據(jù)需求臨時擴容服務(wù)器,等到需求回落了再把服務(wù)器縮減回去。
- 降級指的是服務(wù)降級,這里指的是通過沒那么高級的服務(wù),來緩解瞬時壓力。比方說可以不用上面的隨機數(shù),預(yù)先計算幾千組隨機序列,發(fā)紅包時直接去套已有的隨機序列模板,減少隨機數(shù)生成計算等過程;更進一步的,可以把如
-
如果有人發(fā)現(xiàn),自己發(fā)不了紅包,你該怎么看是哪里出了問題。
答:這里我答的不好,因為我其實懂得不太透徹K8S
那一套,所以我開始胡扯。我說可以把行為分段,即用戶段,消息隊列段,后臺服務(wù)器段,以及數(shù)據(jù)庫段。- 用戶段可以看是局部現(xiàn)象,還是一個全局現(xiàn)象,如果僅是某臺用戶設(shè)備,也說不定是網(wǎng)絡(luò)不良;如果涉及到某一地區(qū),分析是否是區(qū)域供電問題。
- 消息隊列段,如果用戶請求正確到達(dá)消息隊列,說明用戶行為沒錯,核實消息隊列是否正確分發(fā),是否異常丟失。
- 后臺服務(wù)器段,如果消息隊列正常分發(fā),查看是否是某臺服務(wù)器斷線,比如與主機斷連,或由于異常導(dǎo)致的無法服務(wù)等。這一步可以從主機查看從機狀態(tài),也可以使用如
Habor
等工具查看任務(wù)狀態(tài)。 - 數(shù)據(jù)庫段,如果后臺服務(wù)器正常請求,并根據(jù)請求開始操作數(shù)據(jù)庫(交易/轉(zhuǎn)賬等),檢查數(shù)據(jù)庫后臺Log信息是否有誤。
如果此時我們發(fā)現(xiàn)100臺服務(wù)器,就其中的99號機器,所有分發(fā)到這臺設(shè)備上的搶紅包任務(wù),都沒有正常服務(wù),我們該怎么做?
答:把主機上的所有任務(wù)重新放回到消息隊列中,把他從主機上斷連,先確保之后不會再出現(xiàn)未服務(wù)。然后ping
一下測試是否有連接,這里我接著回答的是可以去看日志,是否有異常報錯,在本地執(zhí)行模擬任務(wù),定位問題,不知道有沒有更好的回答方式。
算法題
- 這里的算法題我忘了,放一個八月初阿里的面試算法題好了。說有一個字符串
A
,你每次可以把其中一個字符,拿出來放到字符串末尾,問想轉(zhuǎn)換成字符串B
,最少需要移動幾次(保證A
和B
構(gòu)成元素相同)
答:用A
中所有元素,去和B
的前綴找到最大公共子序列。
int deal(string a, string b){
int index = 0;
for(auto p : a){
if(b[index] == p){
index++;
}
}
return a.length() - index;
}
三面(2021.0830)
基礎(chǔ)題
- 項目介紹
-
K8S
調(diào)優(yōu)接觸過嗎?
答:沒…… - 項目中系統(tǒng)如何實現(xiàn)用戶的高并發(fā)?
答:讓他們在消息隊列里等著。做了一些用戶等待交互。 - 我看到你項目里用到了
Django
,有設(shè)計哪些表嗎?
答:最基礎(chǔ)的有用戶表、任務(wù)表和算法表,然后他們之間分別有一對多關(guān)系,以及還有一些補充表,比方說用戶昵稱表這些與User
相關(guān)的。 - 一個
Django
請求,是怎么發(fā)送給后端的?
答:我這里回答的是HTTP
怎么發(fā)到后端,結(jié)果面試官說他想聽的是,Django
是怎么接收請求的,問我知道WSGI
做了什么嗎?我回答不會。胡亂說了一些MVC
的東西。 - 其他的忘了,但也不是八股的內(nèi)容,屬于兩眼一抹黑,悶頭就是吹的狀態(tài)。
算法題
- 有一棵二叉搜索樹,有一個范圍
[a, b]
,顯式 的把不在該范圍的節(jié)點刪除,返回刪除后二叉搜索樹。
答:這里我的做法是:
void delete_TreeNode(TreeNode* root){
if(root == NULL) return;
// 遞歸刪除所有子樹
delete_TreeNode(root->left);
delete_TreeNode(root->right);
// 這里我是后來百度的才知道該這樣刪除
delete root;
root = NULL;
}
TreeNode* deal(TreeNode* root, int a, int b){
// 判空
if(root == NULL) return NULL;
// root在左邊界以左,則root及其左子樹需全部刪除
if(root->val < a){
delete_TreeNode(root->left);
TreeNode* tmp = root->right;
delete root;
root = NULL;
return deal(tmp, a, b);
}
// 同理root在右邊界以右,則root及其右子樹需全部刪除
if(root->val > b){
delete_TreeNode(root->right);
TreeNode* tmp = root->left;
delete root;
root = NULL;
return deal(tmp, a, b);
}
// root在范圍內(nèi),則遞歸清理兩子樹
root->left = deal(root->left, a, b);
root->right = deal(root->right, a, b);
}