[面試攻略] 技術性考題:鏈表(Linked List)

更新 發佈閱讀 13 分鐘

鏈表是一種線性資料結構,由一系列節點組成,每個節點儲存一個值和指向下一個節點的參考。與陣列不同,鏈表的記憶體不連續,適合動態插入和刪除操作。在技術面試中,鏈表題目經常出現,因為它考驗你對資料結構和程式設計邏輯的掌握。本文將以反轉單向鏈表為例,介紹鏈表基礎、Python實現、時間與空間複雜度,並概述其他常見題目,提供面試答題技巧。


什麼是單向鏈表?

單向鏈表就像一列火車:每節車廂(節點)載著一個乘客(值),並連接到下一節車廂(下一個節點)。最後一節車廂沒有下一節,指向空(None)。

  • 節點結構: 值(val):儲存資料,例如數字或字串。 下一個節點(next):指向下一個節點的參考。
  • 頭節點:鏈表的起點,通過它可以遍歷整個鏈表。
  • 尾節點:最後一個節點,next 為 None。

Python節點定義

class ListNode:
def __init__(self, val=0, next=None):
self.val = val # 節點的值
self.next = next # 下一個節點的參考

核心題目:反轉單向鏈表

問題描述

給定一個單向鏈表,將其反轉並返回新的頭節點。例如:

輸入: 1 -> 2 -> 3 -> 4 -> 5 -> None
輸出: 5 -> 4 -> 3 -> 2 -> 1 -> None

要求:在原地反轉(不創建新鏈表,空間複雜度為 O(1))。

簡單比喻

想像一串珍珠項鍊,你需要把珍珠的順序反過來,但不能拆下珍珠再重串(不能用額外空間)。你只能改變每顆珍珠的「指向」,讓它連到前一顆而不是後一顆。

解法:迭代方法

反轉鏈表最簡單的方法是迭代,使用三個變數逐步改變節點的指向:

  1. 初始化: prev:前一個節點,初始為 None(因為反轉後原頭節點會指向 None)。 curr:當前節點,初始為頭節點。
  2. 遍歷: 儲存下一個節點(next = curr.next),避免斷鏈。 將當前節點指向前一個節點(curr.next = prev)。 移動 prev 和 curr(prev = curr, curr = next)。
  3. 結束: 當 curr 為 None 時,prev 是新頭節點。

程式碼範例

class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next

def reverseList(head):
prev = None # 前一個節點
curr = head # 當前節點
while curr:
next_node = curr.next # 儲存下一個節點
curr.next = prev # 反轉指向
prev = curr # 移動 prev
curr = next_node # 移動 curr
return prev # 新頭節點

# 輔助函數:創建鏈表
def createList(arr):
if not arr:
return None
head = ListNode(arr[0])
curr = head
for val in arr[1:]:
curr.next = ListNode(val)
curr = curr.next
return head

# 輔助函數:列印鏈表
def printList(head):
while head:
print(head.val, end=" -> ")
head = head.next
print("None")

# 測試
arr = [1, 2, 3, 4, 5]
head = createList(arr)
print("原始鏈表:", end=" ")
printList(head) # 輸出: 1 -> 2 -> 3 -> 4 -> 5 -> None
head = reverseList(head)
print("反轉後鏈表:", end=" ")
printList(head) # 輸出: 5 -> 4 -> 3 -> 2 -> 1 -> None

程式碼解釋

  • 節點類:ListNode 定義值和下一節點的參考。
  • 反轉邏輯:
    • 用 prev 和 curr 追蹤鏈表,逐步改變 next 指向。
    • next_node 確保不丟失下一個節點。
  • 輔助函數:
    • createList:從陣列創建鏈表,方便測試。
    • printList:列印鏈表內容,驗證結果。
  • Python優勢:無需手動管理記憶體(不像C/C++需要 malloc 和 free)。

時間與空間複雜度

  • 時間複雜度:O(n),其中 n 是鏈表長度,遍歷每個節點一次。
  • 空間複雜度:O(1),僅使用固定數量的變數(prev, curr, next_node)。

解法:遞迴方法

如果面試官要求遞迴解法,這裡提供一個簡單的遞迴實現:

解法:遞迴

  1. 遞迴到鏈表末端(最後一個節點成為新頭節點)。
  2. 從末端開始,將每個節點的 next 指向前一個節點。
  3. 返回新頭節點。

程式碼範例

def reverseList(head):
# 基本情況:空鏈表或單節點
if not head or not head.next:
return head
# 遞迴反轉剩餘部分
new_head = reverseList(head.next)
# 將當前節點連接到前一個節點
head.next.next = head
head.next = None
return new_head

時間與空間複雜度

  • 時間複雜度:O(n),遍歷每個節點。
  • 空間複雜度:O(n),因為遞迴棧的深度與鏈表長度成正比。

面試Tips

  • 迭代方法更常見,因為空間效率高(O(1))。
  • 如果使用遞迴,強調你理解兩種方法,並提到遞迴的空間開銷。

其他常見鏈表面試題目

面試中可能出現的鏈表題目多種多樣,以下是幾個高頻題目,幫助你全面準備:

  • 檢測鏈表是否有環(Linked List Cycle)
    • 問題:判斷鏈表是否有環(某節點的 next 指向先前節點)。
    • 解法:快慢指標(Floyd's Tortoise and Hare),快指標每次走兩步,慢指標走一步,若相遇則有環。
    • 複雜度:時間 O(n),空間 O(1)。
    • 範例:LeetCode #141。
  • 合併兩個有序鏈表(Merge Two Sorted Lists)
    • 問題:將兩個有序鏈表合併為一個有序鏈表。
    • 解法:逐一比較兩個鏈表的節點,選擇較小值連接到結果鏈表。
    • 複雜度:時間 O(n + m)(n 和 m 是兩鏈表長度),空間 O(1)(不計輸出)。
    • 範例:LeetCode #21。
  • 找到鏈表中間節點(Middle of the Linked List)
    • 問題:返回鏈表的中間節點(若長度為偶數,返回第二個中間節點)。
    • 解法:快慢指標,快指標走兩步,慢指標走一步,當快指標到達末尾,慢指標在中間。
    • 複雜度:時間 O(n),空間 O(1)。
    • 範例:LeetCode #876。
  • 刪除倒數第N個節點(Remove Nth Node From End)
    • 問題:給定 n,刪除鏈表倒數第 n 個節點。
    • 解法:快慢指標,快指標先走 n 步,然後一起走直到快指標到達末尾,慢指標指向待刪除節點的前一個節點。
    • 複雜度:時間 O(n),空間 O(1)。
    • 範例:LeetCode #19。
  • 合併K個有序鏈表(Merge K Sorted Lists)
    • 問題:合併 k 個有序鏈表。
    • 解法:使用最小堆(Priority Queue)或分治法,每次選最小節點。
    • 複雜度:時間 O(n * k * log k)(堆方法),空間 O(k)。
    • 範例:LeetCode #23。

面試應答策略

  • 理解題目:
    • 確認鏈表類型(單向、雙向、是否有環)。
    • 問清楚是否需要處理邊界情況(空鏈表、單節點)。
    • 確認空間複雜度要求(例如,反轉是否必須 O(1) 空間)。
  • 講解思路:
    • 用簡單比喻(火車、珍珠項鍊)讓面試官明白你的思考。
    • 畫圖展示節點和指向變化(例如,反轉時畫出 prev -> curr -> next)。
    • 提到時間和空間複雜度,解釋為什麼選擇某種方法(迭代 vs 遞迴)。
  • 程式碼實現:
    • 寫乾淨的程式碼,使用有意義的變數名(prev, curr, next_node)。
    • 註釋關鍵步驟,特別是改變 next 指向的部分。
    • 處理邊界情況(空鏈表:if not head: return None)。
  • 進階討論:
    • 如果問到優化,提到:
      • 快慢指標在檢測環或找中間節點中的應用。
      • 空間與時間的權衡(迭代節省空間,遞迴更簡潔但耗空間)。
    • 討論實際應用:
      • 鏈表用於動態資料(如瀏覽器歷史記錄)。
      • 與陣列的比較(鏈表插入快,隨機存取慢)。
    • 如果使用Python,提到垃圾回收自動處理記憶體,與C/C++的區別。
  • 常見追問:
    • 「如果鏈表有環怎麼辦?」
      • 回答:先用快慢指標檢測環,若無環再反轉;若有環,需找到環入口並斷開。
    • 「如何優化記憶體使用?」
      • 回答:迭代方法已是最優(O(1) 空間);遞迴可用尾遞迴優化(但Python不支援)。
    • 「Python與C++實現的區別?」
      • 回答:Python無需手動管理記憶體,節點是物件;C++需用指標並小心記憶體洩漏。
  • 模擬面試準備:
    • 在LeetCode練習鏈表題目(#206 Reverse Linked List, #141 Linked List Cycle, #21 Merge Two Sorted Lists)。
    • 手寫程式碼,模擬白板環境,練習邊寫邊講解。
    • 測試邊界情況(空鏈表、單節點、兩個節點)。
    • 熟悉Python的物件參考,確保不誤用賦值(如 curr = curr.next 不會複製節點)。

進階範例:檢測鏈表是否有環

以下是一個常見進階題目的Python實現,展示快慢指標的應用:

問題:檢測鏈表是否有環

def hasCycle(head):
if not head or not head.next:
return False
slow = head # 慢指標
fast = head # 快指標
while fast and fast.next:
slow = slow.next # 慢指標走一步
fast = fast.next.next # 快指標走兩步
if slow == fast: # 相遇表示有環
return True
return False

說明

  • 快慢指標:像兩個人跑步,快的人(fast)每次走兩步,慢的人(slow)走一步。如果有環,他們最終會相遇。
  • 邊界:檢查空鏈表或單節點,無環直接返回 False。
  • 複雜度:時間 O(n),空間 O(1)。

面試Tips

  • 畫圖展示快慢指標的移動,強調「相遇」的邏輯。
  • 如果問到「如何找到環的入口」,提到延伸解法:相遇後讓慢指標回到頭部,兩指標以相同速度走,相遇點即環入口。

結語

鏈表是面試中的必考資料結構,反轉鏈表是最基礎且經常出現的題目,掌握它能為其他題目打下基礎。使用Python實現鏈表題目時,重點在於理解節點參考的改變和邊界處理。練習時,專注於迭代解法(空間效率高),並熟悉快慢指標等技巧。模擬面試時,練習用簡單語言解釋(例如,火車比喻),並確保程式碼乾淨且正確。其他題目如檢測環或合併鏈表也很常見,建議在LeetCode上多練幾題。祝你面試順利!



留言
avatar-img
追極光的北極熊|軟體工程師的小天地
16會員
170內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/05/22
i++(後置遞增)和++i(前置遞增)是C++中用來增加變數值的運算子,兩者在功能上相似但行為有細微差異。這個問題經常出現在技術面試中,因為它涉及運算子的返回值和執行效率。以下將以淺顯的方式解釋它們的差異、提供C++程式碼範例,並分享面試答題技巧。
2025/05/22
i++(後置遞增)和++i(前置遞增)是C++中用來增加變數值的運算子,兩者在功能上相似但行為有細微差異。這個問題經常出現在技術面試中,因為它涉及運算子的返回值和執行效率。以下將以淺顯的方式解釋它們的差異、提供C++程式碼範例,並分享面試答題技巧。
2025/05/16
函數指標(Function Pointer)是一個常見的技術面試題目,特別在C或C++相關的職位中,用來考驗你對程式設計中函數作為一等公民(first-class citizen)的理解,以及記憶體管理和程式控制流的掌握。
2025/05/16
函數指標(Function Pointer)是一個常見的技術面試題目,特別在C或C++相關的職位中,用來考驗你對程式設計中函數作為一等公民(first-class citizen)的理解,以及記憶體管理和程式控制流的掌握。
2025/05/10
在C++中,函數執行時的記憶體配置涉及程式如何在記憶體中儲存變數、參數和程式碼。這是面試常見題目,因為它直接關係到程式效率和資源管理。本文將介紹函數記憶體配置的基礎、C++程式碼範例、關鍵概念,以及面試答題技巧。
2025/05/10
在C++中,函數執行時的記憶體配置涉及程式如何在記憶體中儲存變數、參數和程式碼。這是面試常見題目,因為它直接關係到程式效率和資源管理。本文將介紹函數記憶體配置的基礎、C++程式碼範例、關鍵概念,以及面試答題技巧。
看更多
你可能也想看
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
題目敘述 題目給定一個鏈結串列中的節點Node,要求我們從鏈結串列中刪除該節點。 題目保證該節點不是tail node。 題目要求我們in-place原位操作。 原本的英文題目敘述 測試範例 Example 1: Input: head = [4,5,1,9], node = 5
Thumbnail
題目敘述 題目給定一個鏈結串列中的節點Node,要求我們從鏈結串列中刪除該節點。 題目保證該節點不是tail node。 題目要求我們in-place原位操作。 原本的英文題目敘述 測試範例 Example 1: Input: head = [4,5,1,9], node = 5
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
題目敘述 題目會給定一個鏈結串列的起始點,要求我們把其中區間總和為0的部分刪除掉。 例如 1→ 2 → -2 → 3 → 4 裡面有一段是2 → -2 區間總和為零,所以簡化刪除後變成 1→ 3 → 4 題目的原文敘述 測試範例 Example 1: Input: head
Thumbnail
題目敘述 題目會給定一個鏈結串列的起始點,要求我們把其中區間總和為0的部分刪除掉。 例如 1→ 2 → -2 → 3 → 4 裡面有一段是2 → -2 區間總和為零,所以簡化刪除後變成 1→ 3 → 4 題目的原文敘述 測試範例 Example 1: Input: head
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
給定一個Linked list鏈結串列的Head node, 請判斷這條Linked list是否存在環路(Cycle)? 如果有環路,回傳True。 如果沒有,回傳False。
Thumbnail
給定一個Linked list鏈結串列的Head node, 請判斷這條Linked list是否存在環路(Cycle)? 如果有環路,回傳True。 如果沒有,回傳False。
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
題目敘述 題目會給定一個鏈結串列 Linked List的頭部結點,要求我們根據索引的奇偶數重新排列。奇數索引的在前,偶數索引的在後。數的時候,從Head節點的索引=1開始數。 例如: 1 -> 2 -> 3 -> 4 -> 5 重新排列為 1 -> 3 -> 5 -> 2 -> 4
Thumbnail
題目敘述 題目會給定一個鏈結串列 Linked List的頭部結點,要求我們根據索引的奇偶數重新排列。奇數索引的在前,偶數索引的在後。數的時候,從Head節點的索引=1開始數。 例如: 1 -> 2 -> 3 -> 4 -> 5 重新排列為 1 -> 3 -> 5 -> 2 -> 4
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News