面試不可不會的單鏈表反轉

  • 2021 年 2 月 17 日
  • 筆記

鏈表反轉是面試中常考的一道題,這道題看起來簡單,但是能一遍寫出 bug free 的程式碼相當不容易,本文主要提供遞歸和迭代兩種解題方法,供大家參考。

題目

 

 

 

舉栗

 為了便於理解,以 1->2->3->NULL 為栗子,如下圖示:

 

遞歸解法

鏈表具有天然的遞歸性,一個鏈表例如:1->2->3->NULL,可以看成以值為 1 的節點作為頭節點後面掛接一個更短的(以值為 2 的節點為頭節點)的鏈表,即1->更短的鏈表(以值為2的節點作為頭節點),同理以值為2的節點作為頭節點後面也掛接一個更更短的鏈表(以值為3的節點作為頭節點);依次類推,如下圖示。

 

 

 

 有了這樣的思考,鏈表反轉就可以先翻轉頭節點後面掛接的更短的鏈表,然後再在翻轉後的更短鏈表的後面掛接之前的頭節點。具體如下圖示:

 

 Show me the Code

// C語言版本
struct ListNode* reverseList(struct ListNode* head){
    /* 特判 */
    if (head == NULL || head->next == NULL) {
        return head;
    }
    
    /* 翻轉頭節點(節點值為 1 的節點) 後面掛接的鏈表(以節點值為 2 的節點作為頭節點) */
    /* 翻轉之後變成 3->2 */
    struct ListNode *node = reverseList(head->next); 
    /* 將頭節點(節點值為 1 的節點)掛接在翻轉之後的鏈表的後面(也就是節點值為 2 的節點的後面) */     
    head->next->next = head; 
    /* 將尾節點的下一節點置空 */                            
    head->next = NULL;                               
    return node;
}

  

#python3 版本
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head or not head.next: return head
        node = self.reverseList(head.next)
        head.next.next = head;
        head.next = None;
        return node;

迭代(雙指針)解法

可以用雙指針來做,用一個指針 next 記錄當前節點的後一節點,另外一個指針 pre 記錄當前節點的前一個節點,如果當前節點是頭節點,則 pre 為空指針,還是以鏈表:1->2->3->NUL為栗子,具體如下圖示。

 

 

 

 

 

Show me the Code

// C語言版本
struct ListNode* reverseList(struct ListNode* head){
    /* 記錄當前節點的前一節點 */
    struct ListNode* pre = NULL; 
    while (head != NULL) {
        /* 記錄當前節點的後一節點 */
        struct ListNode* next = head->next;
        head->next = pre;
        pre = head;
        head = next;
    }
    return pre;
}

  

// go語言版本
func reverseList(head *ListNode) *ListNode {
    var pre *ListNode = nil
    for head != nil {
        next := head.Next
        head.Next = pre;
        pre = head
        head = next
    }
    return pre
}