Google 資深工程師蘇勇:算法面試6大數據結構必考知識點!

在互聯網行業的算法面試中常常會被考到數據結構的知識,它與算法相輔相成,沒有紮實的數據結構基礎,學好算法幾乎不太可能。前端

這裏精心整理了 Google 資深工程師的學習筆記和解題技巧,總結出6大數據結構必考知識點,同時以力扣 LeetCode 經典題輔助講解,幫助你更好的理解數據結構要點。面試

 


> 1、數據結構、字符串算法

 

數組和字符串是最基本的數據結構,在不少編程語言中都有着十分類似的性質,這部分的算法面試題也是最多的。編程

不少時候,在分析字符串相關面試題的過程當中,要針對字符串當中的每個字符進行分析和處理,甚至有時候須要先把給定的字符串轉換成字符數組以後再進行分析和處理。舉個最簡單的例子:翻轉一個字符串。後端

一種比較快速和直觀的方法是用兩個指針,一個指向字符串的第一個字符a,一個指向它的最後一個字符m,而後互相交換。交換以後,兩個指針向中央一步步地靠攏並相互交換字符,直到兩個指針相遇。因爲沒法直接修改字符串裏的字符,因此必須先把字符串變換爲數組,而後再運用這個算法。數組

採用數據的優缺點前端工程師

a.優勢:數據結構

構建一個數組很是簡單;編程語言

能讓咱們在 O(1)的時間裏根據數組的下標(index)查詢某個元素。學習

b.缺點:

構建時必須分配一段連續的空間;

查詢某個元素是否存在時須要遍歷整個數組,耗費O(n)的時間(其中,n是元素的個數);

刪除和添加某個元素時,一樣須要耗費O(n)的時間。

因此,在考慮是否應當採用數組去輔助所用算法時,務必須要考慮它的優缺點,看看它的缺點是否會阻礙所用算法的複雜度以及空間複雜度。

真題:力扣(LeetCode)第242題.Valid Anagram 判斷兩個字符串是否互爲字謎

 

解題思路:

所謂字謎,也就是兩個字符串中的相同字符的數量要對應相等。例如:s 等於 「anagram」,t等於 「nagaram」,s和t就互爲字謎,由於它們都包含有三個字符a,一個字符g,一個字符m,一個字符n以及一個字符r。而當s爲「rat」,t爲 「car」的時候,s和t不互爲字謎。

 

題目裏有一個重要的前提:假設兩個字符串只包含小寫字母。小寫字母一共26個,這意味着,能夠利用兩個個長度都爲26的字符數組來統計每一個字符串中小寫字母出現的次數,而後再對比看看是否相等便可。

 

或者,也能夠只利用一個長度爲26的字符數組,將出如今字符串s裏的字符個數加一,而出如今字符串t裏的字符個數減一,最後判斷每一個小寫字母的個數是否都爲零就能夠了。

 


 

 

> 2、鏈表

鏈表的出如今某種程度上是爲了不數組的一大缺陷,即分配數組的時候須要開闢一段連續的內存空間,但魚和熊掌不可兼得,鏈表也犧牲了數組的一些優勢,鏈表不能經過下標進行快速查詢。因此在考慮是否須要運用鏈表的時候,務必搞懂所用算法是否須要常常進行查詢和遍歷。

 

1.鏈表的優勢和缺點

a.優勢:

鏈表能靈活地分配內存空間

能在O(1)時間內刪除或者添加元素,前提是該元素的前一個元素已知,固然也取決因而單鏈表仍是雙鏈表,在雙鏈表中,若是已知該元素的後一個元素,一樣能夠在O(1)時間內刪除或者添加該元素。

b.缺點:

查詢第k個元素須要O(k)時間

很顯然,若是要解決的問題裏面須要不少快速的查詢,鏈表可能並不適合。通常而言,若是數據的元素個數不肯定,並且須要常常進行數據的添加和刪除,那麼鏈表會比較合適,而若是數據元素大小肯定,刪除插入的操做並很少,那麼數組可能更適合。

 

2.鏈表的經典解題方法

a.利用快慢指針(有時候須要用到三個指針):

例如,鏈表的翻轉,尋找倒數第k個元素,或者尋找鏈表中間位置的元素,判斷鏈表是否有環等等。

 

b.構建一個虛假的鏈表頭:

這個方法通常用在要返回新的鏈表的題目中,例如:

給定兩個排好序的鏈表,要求將它們整合在一塊兒並排好序

將一個鏈表中的奇數和偶數按照原定的順序分開後從新組合成一個新的鏈表,鏈表的頭一半是奇數,後一半是偶數。

 

在這類問題裏,若是不用一個虛假的鏈表頭,那麼在建立新鏈表的第一個元素時,都虛要判斷一下鏈表的頭指針是否爲空,也就是要多寫一條if else語句,比較簡潔的寫法是建立一個空的鏈表頭,直接往其後面添加元素便可,最後返回這個空的鏈表頭的下一個節點便可。

另外,鏈表有單鏈表和雙鏈表,它們是實現不少複雜數據結構的基礎,在解決鏈表的題目時,建議在紙上或者白板上畫出節點之間的相互關係,而後畫出修改的方法,這樣能夠有效地分析問題,由於憑空想象是比較困難的,並且在面試的時候,若是能把方法畫在白板上,還能幫助面試官清楚地看到你的思路。

真題:力扣(LeetCode)第25題.Reverse Nodes in k-Group在鏈表中對每k個節點所組成的部分進行翻轉

clipboard.png

這道題是力扣(LeetCode)第24題.Swap Node in Paris(在鏈表中每兩個節點進行翻轉)的擴展,在這道題裏,當k等於2時,第25題就變成了第24題。

那麼這道題考察了兩個知識點:

你對鏈表翻轉算法是否熟悉

你對遞歸算法的理解是否清晰

在翻轉鏈表的時候,咱們能夠藉助三個指針:prev、curr、next,分別表明了前一個節點、當前節點和下一個節點。

最爲重要的是,當完成了局部的翻轉後,prev就是最終的新的鏈表頭,curr指向了下一個要被處理的局部,而原來的頭指針head成爲了鏈表的尾巴。

 


 

 

> 3、棧

棧是許多力扣中等難度偏上的題目裏面常常須要用到的數據結構。掌握好它是十分必要的。

 

1.棧的特色

棧的特色就是後進先出(LIFO),對於棧中的數據來講,全部操做都是在棧的頂部完成的,只能夠查看棧頂部的數據,只可以向棧的頂部壓⼊入數據,也只能從棧的頂部彈出數據。

 

所以,能夠利用一個單鏈表來實現棧的數據結構,並且,由於只針對棧頂元素進行操做,因此借用單鏈表的頭就能讓全部棧的操做在O(1)的時間內完成。雖然能夠用一個數組外加一個指針也能實現類似的效果,可是,一旦數組的長度發生了改變,哪怕只是在最後添加一個新的元素,時間複雜度再也不是O(1),並且,空間複雜度也得不到優化。

2.何時須要用到棧呢?

圍繞棧的算法面試題不少,基本的核心思想就是:當解決某個問題的時候,只關心最近一次的操做,而且在操做完成了以後,須要向前查找到更前一次的操做。

 

例如,給出了一串由左括號和右括號組成的字符串,須要判斷這些括號的組成是否合法。方法就是能夠利用一個棧,不斷地往裏壓左括號,一旦趕上了一個右括號,就把棧頂的左括號彈出來,表示這是一個合法的組合,以此類推,直到最後判斷棧裏還有沒有左括號剩餘。

真題:力扣(LeetCode)第739題.Dailey Temperatures氣溫變化

解題思路:

給定一個數組 T 表明了將來幾天裏天天的溫度值,要求返回一個新的數組D,D中的每一個元素表示須要通過多少天才能等來溫度的升高。例如:

給定T:[23,25,21,19,22,26,23]

返回D:[1,4,2,1,1,0,0]

 

最直觀的作法就是針對每一個溫度值向後進行以此搜索,找到比當前溫度更高的值,這樣的計算複雜度就是O(n^2)。

在這樣的搜索過程當中,產生了不少重複的對比,從25度開始日後面尋找一個比25度更高的溫度的過程當中,前後經歷了21度,19度和22度,這是一個溫度由低到高的過程,也就是在這個過程當中已經找到了19度以及21度的答案了,就是22度。

 

能夠運用一個堆棧Stack來快速地知道須要通過多少天就能等到溫度升高。基本的思想是從頭至尾掃描一遍給定的數組T,若是當天的溫度比堆棧Stack頂端所記錄的那天溫度還要高,那麼就能知道結果了。

 

 

這是一道比較有意思的題目,建議到力扣(LeetCode)上試試。

 

利用堆棧,還能夠幫助解決以下常見的問題:

判斷一系列括號的組合是否合法 【力扣(LeetCode)20】

求解算術表達式的結果【力扣(LeetCode)224,227,772,770】

求解直方圖裏最大的矩形區域【力扣(LeetCode)84】


 

 

> 4、隊列

1.隊列的特色

隊列的最大特色是先進先出(FIFO),就好像按順序排隊同樣。對於隊列的數據來講,只容許在隊尾查看和添加數據,在隊頭查看和刪除數據。

2.如何實現一個隊列

能夠藉助雙鏈表實現隊列,雙鏈表的頭指針容許在隊頭查看和刪除數據,而雙鏈表的尾指針容許在隊尾查看和添加數據。當須要按照必定的順序來處理數據,而要處理的數據量在不斷地變化的時候,就須要使用隊列。在算法面試題當中,廣度優先搜索(Breadth-First Search)是運用隊列最多的地方。


 

 

5、雙端隊列

雙端隊列和普通隊列最大的不一樣在於,它容許在隊列的頭尾兩端都能在O(1)的時間內進行數據的查看、添加和刪除。

 

與隊列類似,能夠利用一個雙鏈表來實現雙端隊列。

 

雙端隊列最經常使用的地方就是實現一個長度動態變化的窗口或者連續區間,而動態窗口這種數據結構在不少題目裏都有運用。下面經過一道經典的例題來分析它的用法。

真題:力扣(LeetCode)第239題.Sliding Window Maximum 尋找滑動窗口中的最大值

解題思路:

給定一個數組以及一個窗口的長度 k,如今移動這個窗口,要求打印出一個數組,數組裏的每一個元素是當前窗口當中最大的那個數。例如:

 

輸入:nums=[1,3,-1,-3,5,3,6,7],k=3

輸出:[3,3,5,5,6,7]

 

能夠利用一個雙端隊列來保存當前窗口中最大那個數在數組裏的下標,有了這個下標,就能很快地知道新的窗口是否已經再也不包含原來那個最大的數,若是再也不包含,就把舊的數從雙端隊列的頭刪除,而雙端隊列新的頭就是當前窗口中最大的那個數。按照這樣的操做,咱們能夠在O(n)的時間裏完成全部任務。

 

在這道題當中,咱們須要頻繁地進行兩個操做:

1、將新的數據加入到窗口的尾部

2、將舊的數據從窗口頭部刪除

 

雙端隊列,它能讓上面的這兩種操做都能在O(1)的時間裏完成,使整個算法的複雜度能控制在O(n)。


 

 

> 6、樹

樹的結構十分直觀,而樹的不少概念定義都有一個相同的特色:遞歸,也就是說,一棵樹要知足某種性質,每每要求每一個節點都必須知足。例如,在定義一棵二叉搜索樹時,每一個節點也都必須是一棵二叉搜索樹。正由於樹有這樣的性質,大部分關於樹的面試題都與遞歸有關,換句話說,面試官但願經過一道關於樹的問題來你對於遞歸算法掌握的熟練程度。

 

在面試中常考的樹的形狀有:普通二叉樹、平衡二叉樹、徹底二叉樹、二叉搜索樹、四叉樹(Quadtree)、多叉樹(N-ary Tree)。

 

對於一些特殊的樹,例如紅黑樹(Red-Black Tree)、自平衡二叉搜索樹(AVL Tree),你們沒必要花費太多時間去準備,通常在面試中不會被問到,除非你所涉及的研究領域跟它們相關或者你十分感興趣。

 

關於樹的考題,無非就是要考查樹的遍歷以及序列化(serialization)。樹的基本遍歷有三種:前序遍歷(Preorder Traversal)、中序遍歷(Inorder Traversal)以及後序遍歷(Postorder Traversal)。掌握好這三種遍歷的遞歸寫法和非遞歸寫法是很是重要的,同時,懂得分析各類寫法的時間複雜度和空間複雜度一樣重要。

 

不管你是前端工程師,仍是後端工程師,在準備面試的時候,樹這個數據結構能夠說是最應該花時間學習的。掌握好樹,能證實你對遞歸有很好的認識,能幫助你學習圖論。另外,樹的許多性質都是面試的熱門考點,尤爲是二叉搜索樹(BST)。

 

下面能夠經過一道例題來看看樹的考察點。

真題:力扣(LeetCode)第230題.Kth Smallest Element Element in a BST在一棵二叉搜索樹中尋找第k小的元素

解題思路:

這道題考察了兩個知識點:

1、二叉搜索樹的性質

2、二叉搜索樹的遍歷

二叉搜索樹的中序遍歷能夠說是二叉搜索樹性質裏最喜歡被考的知識點,由於節點被遍歷到的順序是按照節點數值大小的順序排列好的。也就意味着,按照中序遍歷一次這個二叉搜索樹,遍歷當中遇到的元素都是按照從小到大的順序出現。採用這個知識點,只須要對這棵樹進行中序遍歷的操做,當訪問到第k個元素的時候返回結果就好。

另外,這道題能夠變成求解第k大的元素,方法就是對這個二叉搜索樹進行反向的中序遍歷,那麼數據的被訪問順序就是由大到小了。

 

內容摘取自《300分鐘搞定算法面試》,戳此查看更多

第01講:經常使用數據結構

主講人:蘇勇,谷歌資深技術工程師

添加amy好友:lagouandy,回覆【算法】,可領取電子書等求職禮包

相關文章
相關標籤/搜索