《关于我的那些面经》——百度后端(附答案)
作者保證,本系列全是純干貨真實記錄,絕對不是某些營銷號瞎編亂造的面試。
一、公司的簡介
百度是全球最大的中文搜索引擎,是中國最大的以信息和知識為核心的互聯網綜合服務公司,更是全球領先的人工智能平臺型公司。2000年1月1日創立于中關村,公司創始人李彥宏擁有“超鏈分析”技術專利,也使中國成為美國、俄羅斯、和韓國之外,全球僅有的4個擁有搜索引擎核心技術的國家之一。
百度作為全球最大的中文搜索引擎,百度每天響應來自100余個國家和地區的數十億次搜索請求,是網民獲取中文信息的最主要入口。百度以“用科技讓復雜的世界更簡單”為使命,不斷堅持技術創新,致力于“成為最懂用戶,并能幫助人們成長的全球頂級高科技公司”。
百度是中國最大的以信息和知識為核心的互聯網綜合服務公司。在AI驅動下,百度的移動生態是中國最大的以信息和知識為核心的移動生態,以百家號、智能小程序和托管頁為主要支柱。2019年百度用戶規模突破10億。百度App日活躍用戶2.22億,信息流位居中國第一。百家號創作者達到300萬。百度智能小程序是國內唯一完全開源的小程序平臺,月活用戶規模破3.54億。百度知道、百度百科、百度文庫等六大知識類產品累計生產超10億條高質量內容,構建了中國最大的知識內容體系。
百度是全球領先的人工智能平臺型公司。百度大腦是中國唯一的“軟硬一體AI大生產平臺”,是百度AI的集大成,對外全方位輸出超過250多項AI能力。飛槳是中國首個全面開源開放、功能完備的產業級深度學習平臺,是中國自主研發的“智能時代的操作系統”。百度智能云是百度AI To B業務的重要承載者和輸出者,是產業智能化領導者。小度助手是中國最大的對話式人工智能操作系統,擁有中國市場規模最大、最繁榮的對話式人工智能生態,2020年3月,小度助手語音交互次數超過65億次。作為全球最大自動駕駛開放平臺,Apollo代表中國最強自動駕駛實力,被知名研究公司Navigant Research列為全球四大自動駕駛領域領導者之一。目前已形成自動駕駛、車路協同、智能車聯三大開放平臺。自動駕駛方面,超過十項中國第一,技術實力領跑行業。智能交通方面,百度“ACE交通引擎”是全球首個車路行融合的全棧式智能交通解決方案。
?
廢話少說BATTMD哪個公司不是吹的天花亂墜,直接看工資
校招
SP代表special offer
SSP的offer級別還在SP之上
一般情況下薪資專欄中的18*15
是指1.8w一個月,一年總共15個月
其中15一般是13個月工資,包括2個月的年終獎
簡單科普結束以后我們來看看數據吧
這是碩士的薪資,本科的自行減去1-2k,測試崗也是從研發減去1-2k。
社招
薪資方面呢,在BATTMD中不算很有競爭力,但是今年還是漲了不少,算是很有誠意,適合喜歡所謂“技術”以及沒有更好選擇的同學去。
二、對公司的評價
產品之神俞軍在移動互聯網前夕走了,百度在10-20掉隊了,這是不可否認的事實。但是最近兩年,百度一直在改變,押寶在無人車上。去年股票也確實表現不錯,暫時可以堅持下去。
市值:1145億美元(比去年翻了不止一倍,之前還以為他涼涼了)
三、面試過程
1)如何判斷鏈表是否有環?
像模像樣的要我現場寫了一遍,說了一遍思路。
為了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。
?
示例 2:
輸入:head = [1], pos = -1
輸出:false
解釋:鏈表中沒有環。
進階:
你能用?O(1)(即,常量)內存解決此問題嗎?
?
思路:首先我們要明白,鏈表不可能出現這種情況:
因為一個結點只有一個指針,所以鏈表只可能向實例一那樣,在末尾出現一個環。
慢指針一次一步,快指針一次兩步。能相遇就是有環,反之沒有環。就像操場跑步,跑的快的總有一天可以追慢的一圈,相遇。
/*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val = x;* next = null;* }* }*/ public class Solution {public boolean hasCycle(ListNode head) {if (head == null || head.next == null) {return false;}ListNode slow = head;ListNode fast = head.next;while (slow != fast) {if (fast == null || fast.next == null) {return false;}slow = slow.next;fast = fast.next.next;}return true;} }那么,這對于懂算法的人來說可能是爛大街的問題,有些人可能不屑于看了,那么,第二個問題來了:如果讓那個快指針一次走三步,還能不能做正確的答案呢?一次四步呢?五步呢?
如果看的人多,我會在下一期公布答案哈哈,大家不要以為應試被題就可以過關。
2)介紹一下堆這種數據結構
大根堆要求
①根節點的關鍵字既大于或等于左子樹的關鍵字值,又大于或等于右子樹的關鍵字值。
②為完全二叉樹。
注意這是遞歸定義的。
對于大根小根堆,遞歸定義,實現,空間復雜度,各種操作的時間復雜度,真實寫二叉樹的情況和數組模擬的情況都要會。
有人要問了,會這些算法有啥用?其實Java的優先隊列就是堆結構。八大排序之一的堆排序也是數組上堆結構,面試官讓我手動實現一個,以下是實現。
/* ================================================ 功能:堆排序 輸入:數組名稱(也就是數組首地址)、數組中元素個數 注:畫畫 ================================================ */ /* 功能:建堆 輸入:數組名稱(也就是數組首地址)、參與建堆元素的個數、從第幾個元素開始 */ void sift(int *x, int n, int s) {int t, k, j;t = *(x+s); /*暫存開始元素*/k = s; /*開始元素下標*/j = 2*k + 1; /*左子樹元素下標*/while (j<n){if (j<n-1 && *(x+j) < *(x+j+1))/*判斷是否存在右孩子,并且右孩子比左孩子大,成立,就把j換為右孩子*/{j++;}if (t<*(x+j)) /*調整*/{*(x+k) = *(x+j);k = j; /*調整后,開始元素也隨之調整*/j = 2*k + 1;}else /*沒有需要調整了,已經是個堆了,退出循環。*/{break;}}*(x+k) = t; /*開始元素放到它正確位置*/ } /* 功能:堆排序 輸入:數組名稱(也就是數組首地址)、數組中元素個數 注:** ** - * ** * * 建堆時,從從后往前第一個非葉子節點開始調整,也就是“-”符號的位置 */ void heap_sort(int *x, int n) {int i, k, t; //int *p;for (i=n/2-1; i>=0; i--){sift(x,n,i); /*初始建堆*/}for (k=n-1; k>=1; k--){t = *(x+0); /*堆頂放到最后*/*(x+0) = *(x+k);*(x+k) = t;sift(x,k,0); /*剩下的數再建堆*/} }3)排序知道哪些?來介紹介紹?
答:全知道,全會寫,然后只說了冒泡的所有思路和優化、和快排BFPRT就被叫停了。我就把所有排序介紹和實現分享給大家。
全排序
一面結束,面試小哥表示對我很滿意,說馬上讓另外一個人二面。
二面:
二面小哥說,一面說你算法賊強,咱們這次就不聊算法了,說說項目。
4)看我項目里用了redis,就問redis都有哪些數據結構。
我說有string、list、hash、set、zset。
問:你說的這些Java以及其他語言基本也都有,你說了解redis,那這些數據結構到底是不是快?咋實現的呢?
我舉例子說了一下:
- 1) 字符串
redis并未使用傳統的c語言字符串表示,它自己構建了一種簡單的動態字符串抽象類型。
當需要一個可以被修改的字符串時,redis就會使用自己實現的SDS(simple dynamic string)。比如在redis數據庫里,包含字符串的鍵值對底層都是SDS實現的,不止如此,SDS還被用作緩沖區(buffer):比如AOF模塊中的AOF緩沖區以及客戶端狀態中的輸入緩沖區。
下面來具體看一下sds的實現:
struct sdshdr
{
int len;//buf已使用字節數量(保存的字符串長度)
int free;//未使用的字節數量
char buf[];//用來保存字符串的字節數組
};
sds遵循c中字符串以'\0'結尾的慣例,這一字節的空間不算在len之內。
這樣的好處是,我們可以直接重用c中的一部分函數。比如printf;
? ? sds相對c的改進
? ? 獲取長度:c字符串并不記錄自身長度,所以獲取長度只能遍歷一遍字符串,redis直接讀取len即可。
? ? 緩沖區安全:c字符串容易造成緩沖區溢出,比如:程序員沒有分配足夠的空間就執行拼接操作。而redis會先檢查sds的空間是否滿足所需要求,如果不滿足會自動擴充。
? ? 內存分配:由于c不記錄字符串長度,對于包含了n個字符的字符串,底層總是一個長度n+1的數組,每一次長度變化,總是要對這個數組進行一次內存重新分配的操作。因為內存分配涉及復雜算法并且可能需要執行系統調用,所以它通常是比較耗時的操作。? ?
? ? redis內存分配:
1、空間預分配:如果修改后大小小于1MB,程序分配和len大小一樣的未使用空間,如果修改后大于1MB,程序分配? 1MB的未使用空間。修改長度時檢查,夠的話就直接使用未使用空間,不用再分配。?
2、惰性空間釋放:字符串縮短時不需要釋放空間,用free記錄即可,留作以后使用。
? ? 二進制安全
c字符串除了末尾外,不能包含空字符,否則程序讀到空字符會誤以為是結尾,這就限制了c字符串只能保存文本,二進制文件就不能保存了。
而redis字符串都是二進制安全的,因為有len來記錄長度。
這就是redis中string的實現和要點,我大概都給他講了一遍。然后他說你不用說了,又說到算法數據結構了,咱們聊點別的。
5)聊點實際的吧,你一直在吹redis,知道用redis會給你帶來什么問題嗎?
我有點懵,就給他說nosql和傳動數據庫的區別之類的,然后他說你不要給我說這些比較,舉個例子,緩存雪崩聽說過嗎?我就明白他想聊什么了,又給他說了說以下內容。
緩存穿透
一般的緩存系統,都是按照key去緩存查詢,如果不存在對應的value,就去后端系統查找(比如DB)。
一些惡意的請求會故意查詢不存在的key,請求量很大,就會對后端系統造成很大的壓力。這就叫做緩存穿透。
?
如何避免?
1:對查詢結果為空的情況也進行緩存,這樣,再次訪問時,緩存層會直接返回空值。緩存時間設置短一點,或者該key對應的數據insert了之后清理緩存。
2:對一定不存在的key進行過濾。具體請看布隆過濾器
緩存擊穿
是針對緩存中沒有但數據庫有的數據。
場景是,當Key失效后,假如瞬間突然涌入大量的請求,來請求同一個Key,這些請求不會命中Redis,都會請求到DB,導致數據庫壓力過大,甚至扛不住,掛掉。
解決辦法
1、設置熱點Key,自動檢測熱點Key,將熱點Key的過期時間加大或者設置為永不過期,或者設置為邏輯上永不過期
2、加互斥鎖。當發現沒有命中Redis,去查數據庫的時候,在執行更新緩存的操作上加鎖,當一個線程訪問時,其它線程等待,這個線程訪問過后,緩存中的數據會被重建,這樣其他線程就可以從緩存中取值。
緩存雪崩
是指大量Key同時失效,對這些Key的請求又會打到DB上,同樣會導致數據庫壓力過大甚至掛掉。
解決辦法
1)讓Key的失效時間分散開,可以在統一的失效時間上再加一個隨機值,或者使用更高級的算法分散失效時間。
2)構建多個redis實例,個別節點掛了還有別的可以用。
3)多級緩存:比如增加本地緩存,減小redis壓力。
4)對存儲層增加限流措施,當請求超出限制,提供降級服務(一般就是返回錯誤即可)
他說作為一個學生,知道這些知識就可以了,對我比較滿意,說讓三面。
三面面試官看樣子是某個領導,問的比較隨意。
6)輸入網址到看到網頁的過程
答:(能多細就多細,你背答案估計就死了,要理解)域名解析?--> TCP3次握手?--> 發http請求?--> 響應http請求,瀏覽器得到html代碼?--> 瀏覽器解析代碼,請求html代碼中的資源(js、css、圖片等)?--> 瀏覽器對頁面進行渲染呈現給用戶
7)讓手寫快排(我尋思真就沒別的可問了唄)
然后就結束了。
?
四、感受
感覺總體難度一般,問鏈表環問題改成三四步,我是沒想到的,證明面試官有點東西。二面面試官給我的感覺應該也讀過redis源碼,我記錄的應該不全,倆人這方面談的挺投機。整體是挺好的體驗,可能因為也是學長內推的關系,三次面試都像聊天一樣就過去了。手寫算法也基本沒卡殼,平時因為很重視代碼風格。自以為手擼代碼他們也比較滿意。結果就是通過所有面試發了offer,最后沒去。
總結
以上是生活随笔為你收集整理的《关于我的那些面经》——百度后端(附答案)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 保险公司十大排名,各保险公司一览
- 下一篇: 学习笔记3-C语言-基础