[E] 206. 反轉鏈結串列 (Reverse Linked List)
題目
- LeetCode 連結
- 主題:Linked List
- 難度:Easy
題目描述
給定一個單向鏈結串列的頭節點 head
,請反轉該鏈結串列,並回傳反轉後的串列。
範例 1:
範例 2:
範例 3:
限制條件:
- 鏈結串列的節點數量範圍為
[0, 5000]
。 -5000 <= Node.val <= 5000
進階挑戰:
鏈結串列可以透過迭代或遞迴的方式進行反轉。你能實作這兩種方式嗎?
問題釐清
- 輸入型別一定是 ListNode 或空串列的 null 嗎,應該不需要處理不合法輸入?
- 當輸入為 null 時則回傳 null?
- 節點的數量限制在 5000 個內?會需要考慮 stack overflow 的問題嗎?
提出測試案例
- 能通過三個範例
- 節點數量的壓測
提出思路
如果以程式的簡潔程度來實作的話,使用遞迴應該是最快,但如果需要考量較大量的節點數量可能需要改成迭代的方式。這裡先以遞迴方式實作,如果是遞迴的話,關鍵在於找出 base case 與要執行遞迴的剩餘部份。
如果以一個最簡單的例子 1 → 2 → 3 這樣的串列來做圖解的話,步驟會像是這樣:
因此實作上的思路大概會像這樣:
- 處理 base cases:當
head
或head.next
為null
時,代表已經到了尾部,則直接回傳head
這個節點 - 宣告一個新的串列去遞迴處理該節點後的剩餘串列節點
- 反轉當前
head
節點的head.next.next
與head.next
指標 - 回傳處理後的新串列的頭部
以註解表示思路的話會像這樣:
實作
撰寫測試
沿用之前實作的陣列、串列互轉的 util function,可以簡單用 test.each
寫個單元測試像這樣:
在壓測這裡如果嘗試去增加節點數會發現遇到 Maximum call stack size exceeded
的問題,下面再來嘗試用進階挑戰中提到的迭代方式改寫看看。
實作迭代解法
詳細的思路用圖解比較好理解,簡單說就是用兩個指標來依序跑迴圈去不斷重複執行「斷開連結與反轉」直到當前指標指到 null 為止:
實作的話就會像這樣:
複雜度分析
遞迴 | 迭代 | |
---|---|---|
時間複雜度 | O(N) | O(N) |
空間複雜度 | O(N) | O(1) |
說明 | 遞迴會佔用額外的 Call Stack,最多會遞迴到 N 層 (節點數量)。 | 只使用了固定數量的變數 (prev 、curr 、tmpNext ),不會隨著輸入大小增加 |
程式碼
詳細程式碼可以參考此 GitHub 連結。