面試算法實踐與國外大廠習題指南


在線練習

  • LeetCode

  • Virtual Judge

  • CareerCup

  • HackerRank

  • CodeFights


在線面試編程

  • Gainlo


數據結構

Linked List

  • 鏈表即是由節點(Node)組成的線性集合,每個節點可以利用指針指向其他節點。它是一種包含了多個節點的,能夠用於表示序列的數據結構。

  • Singly-linked list: 鏈表中的節點僅指向下一個節點。

  • Doubly-linked list: 鏈表中的節點不僅指向下一個節點,還指向前一個節點。

  • 時間複雜度:

    • 索引: O(n)

    • 搜索: O(n)

    • 插入: O(1)

    • 移除: O(1)


Stack

  • 棧是元素的集合,其包含了兩個基本操作:push 操作可以用於將元素壓入棧,pop 操作可以將棧頂元素移除。

  • 遵循後入先出(LIFO)原則。

  • 時間複雜度:

    • 索引: O(n)

    • 搜索: O(n)

    • 插入: O(1)

    • 移除: O(1)


Queue

  • 隊列是元素的集合,其包含了兩個基本操作:enqueue 操作可以用於將元素插入到隊列中,而 dequeeu 操作則是將元素從隊列中移除。

  • 遵循先入先出原則 (FIFO)。

  • 時間複雜度:

    • 索引: O(n)

    • 搜索: O(n)

    • 插入: O(1)

    • 移除: O(1)


Tree

  • 樹即是無向非循環圖。


Binary Tree

  • 二叉樹即是每個節點最多包含左子節點與右子節點這兩個節點的樹形數據結構。

  • 滿二叉樹: 樹中的每個節點僅包含 0 或 2 個節點。

  • 完美二叉樹: 二叉樹中的每個葉節點都擁有兩個子節點,並且具有相同的高度。

  • 完全二叉樹: 除最後一層外,每一層上的結點數均達到最大值;在最後一層上只缺少右邊的若干結點。


Binary Search Tree

  • 二叉搜索樹(BST)是一種特殊的二叉樹,其任何節點中的值都會大於或者等於其左子樹中存儲的值並且小於或者等於其右子樹中存儲的值。

  • 時間複雜度:

    • 索引: O(log(n))

    • 搜索: O(log(n))

    • 插入: O(log(n))

    • 刪除: O(log(n))


Trie

  • 字典樹,又稱基數樹或者前綴樹,能夠用於存儲鍵爲字符串的動態集合或者關聯數組的搜索樹。樹中的節點並沒有直接存儲關聯鍵值,而是該節點在樹中的掛載位置決定了其關聯鍵值。某個節點的所有子節點都擁有相同的前綴,整棵樹的根節點則是空字符串。


Fenwick Tree

  • 樹狀數組又稱 Binary Indexed Tree,其表現形式爲樹,不過本質上是以數組實現。數組中的下標代表着樹中的頂點,每個頂點的父節點或者子節點的下標能夠通過位運算獲得。數組中的每個元素包含了預計算的區間值之和,在整棵樹更新的過程中同樣會更新這些預計算的值。

  • 時間複雜度:

    • 區間求值: O(log(n))

    • 更新: O(log(n))


Segment Tree

  • 線段樹是用於存放間隔或者線段的樹形數據結構,它允許快速的查找某一個節點在若干條線段中出現的次數.

  • 時間複雜度:

    • 區間查詢: O(log(n))

    • 更新: O(log(n))


Heap

  • 堆是一種特殊的基於樹的滿足某些特性的數據結構,整個堆中的所有父子節點的鍵值都會滿足相同的排序條件。堆更準確地可以分爲最大堆與最小堆,在最大堆中,父節點的鍵值永遠大於或者等於子節點的值,並且整個堆中的最大值存儲於根節點;而最小堆中,父節點的鍵值永遠小於或者等於其子節點的鍵值,並且整個堆中的最小值存儲於根節點。

  • 時間複雜度:

    • 訪問: O(log(n))

    • 搜索: O(log(n))

    • 插入: O(log(n))

    • 移除: O(log(n))

    • 移除最大值 / 最小值: O(1)


Hashing

  • 哈希能夠將任意長度的數據映射到固定長度的數據。哈希函數返回的即是哈希值,如果兩個不同的鍵得到相同的哈希值,即將這種現象稱爲碰撞。

  • Hash Map: Hash Map 是一種能夠建立起鍵與值之間關係的數據結構,Hash Map 能夠使用哈希函數將鍵轉化爲桶或者槽中的下標,從而優化對於目標值的搜索速度。

  • 碰撞解決

    • 鏈地址法(Separate Chaining): 鏈地址法中,每個桶是相互獨立的,包含了一系列索引的列表。搜索操作的時間複雜度即是搜索桶的時間(固定時間)與遍歷列表的時間之和。

    • 開地址法(Open Addressing): 在開地址法中,當插入新值時,會判斷該值對應的哈希桶是否存在,如果存在則根據某種算法依次選擇下一個可能的位置,直到找到一個尚未被佔用的地址。所謂開地址法也是指某個元素的位置並不永遠由其哈希值決定。


Graph

  • 圖是一種數據元素間爲多對多關係的數據結構,加上一組基本操作構成的抽象數據類型。

    • 無向圖(Undirected Graph): 無向圖具有對稱的鄰接矩陣,因此如果存在某條從節點 u 到節點 v 的邊,反之從 v 到 u 的邊也存在。

    • 有向圖(Directed Graph): 有向圖的鄰接矩陣是非對稱的,即如果存在從 u 到 v 的邊並不意味着一定存在從 v 到 u 的邊。

圖片


算法

Sorting

快速排序

  • 穩定: 否

  • 時間複雜度:

    • 最優時間: O(nlog(n))

    • 最壞時間: O(n^2)

    • 平均時間: O(nlog(n))

圖片


合併排序

  • 合併排序是典型的分治算法,它不斷地將某個數組分爲兩個部分,分別對左子數組與右子數組進行排序,然後將兩個數組合併爲新的有序數組。

  • 穩定: 是

  • 時間複雜度:

    • 最優時間: O(nlog(n))

    • 最壞時間: O(nlog(n))`

    • 平均時間: O(nlog(n))

在線動圖:https://github.com/kdn251/interviews/blob/master/Images/mergesort.gif?raw=true


桶排序

  • 桶排序將數組分到有限數量的桶子裏。每個桶子再個別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排序)。

  • 時間複雜度:

    • 最優時間: Ω(n + k)

    • 最壞時間: O(n^2)

    • 平均時間:Θ(n + k)


基數排序

  • 基數排序類似於桶排序,將數組分割到有限數目的桶中;不過其在分割之後並沒有讓每個桶單獨地進行排序,而是直接進行了合併操作。

  • 時間複雜度:

    • 最優時間: Ω(nk)

    • 最壞時間: O(nk)

    • 平均時間: Θ(nk)


圖算法

深度優先搜索

  • 深度優先算法是一種優先遍歷子節點而不是回溯的算法。

  • 時間複雜度: O(|V| + |E|)


廣度優先搜索

  • 廣度優先搜索是優先遍歷鄰居節點而不是子節點的圖遍歷算法。

  • 時間複雜度: O(|V| + |E|)


拓撲排序

  • 拓撲排序是對於有向圖節點的線性排序,如果存在某條從 u 到 v 的邊,則認爲 u 的下標先於 v。

  • 時間複雜度: O(|V| + |E|)


Dijkstra 算法

  • Dijkstra 算法 用於計算有向圖中單源最短路徑問題。

  • 時間複雜度: O(|V|^2)


Bellman-Ford 算法

  • Bellman-Ford 算法 是在帶權圖中計算從單一源點出發到其他節點的最短路徑的算法。

  • 儘管算法複雜度大於 Dijkstra 算法,但是它適用於包含了負值邊的圖。

  • 時間複雜度:

    • 最優時間: O(|E|)

    • 最壞時間: O(|V||E|)


Floyd-Warshall 算法

  • Floyd-Warshall 算法 能夠用於在無環帶權圖中尋找任意節點的最短路徑。

  • 時間複雜度:

    • 最優時間: O(|V|^3)

    • 最壞時間: O(|V|^3)

    • 平均時間: O(|V|^3)


Prim 算法

  • Prim's 算法是用於在帶權無向圖中計算最小生成樹的貪婪算法。換言之,Prim 算法能夠在圖中抽取出連接所有節點的邊的最小代價子集。

  • 時間複雜度: O(|V|^2)


Kruskal 算法

  • Kruskal 算法 同樣是計算圖的最小生成樹的算法,與 Prim 的區別在於並不需要圖是連通的。

  • 時間複雜度: O(|E|log|V|)

圖片


位運算

  • 位運算即是在位級別進行操作的技術,合適的位運算能夠幫助我們得到更快地運算速度與更小的內存使用。

  • 測試第 k 位: s & (1 << k)

  • 設置第 k 位: s |= (1 << k)

  • 第 k 位置零: s &= ~(1 << k)

  • 切換第 k 位值: s ^= ~(1 << k)

  • 乘以 2: s << n

  • 除以 2: s >> n

  • 交集: s & t

  • 並集: s | t

  • 減法: s & ~t

  • 交換 x = x ^ y ^ (y = x)

  • Extract lowest set bit: s & (-s)

  • Extract lowest unset bit: ~s & (s + 1)


算法複雜度分析

大 O 表示

  • 大 O 表示 用於表示某個算法的上限,往往用於描述最壞的情況。

圖片


小 O 表示

  • 小 O 表示 用於描述某個算法的漸進上界,不過二者要更爲緊密。


大 Ω 表示

  • 大 Ω 表示 用於描述某個算法的漸進下界。

圖片

小 ω 表示

  • Little Omega Notation 用於描述某個特定算法的下界,不過不一定很靠近。


Theta Θ 表示

  • Theta Notation 用於描述某個確定算法的確界。

圖片

視頻教程

  • Data Structures

    • UC Berkeley Data Structures

    • MIT Advanced Data Structures

  • Algorithms

    • MIT Introduction to Algorithms

    • MIT Advanced Algorithms


面試書籍

  • Competitive Programming 3 - Steven Halim & Felix Halim

  • Cracking The Coding Interview - Gayle Laakmann McDowell

  • Cracking The PM Interview - Gayle Laakmann McDowell & Jackie Bavaro


計算機科學與技術資訊

  • Hacker News


本文譯自 Kevin Naughton Jr. 維護的倉庫 interviews,包含了在線練習、算法概述與大廠習題實戰等內容。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章