🔁

反轉 Linked List

2022/07/22に公開

完成的程式碼

func reverse(_ listNode: ListNode?) -> ListNode? {
    var previous: ListNode? = nil
    var current = listNode
    var next: ListNode? = nil

    while current != nil {
        next = current?.next
        current?.next = previous
        previous = current
        current = next
    }
    
    return previous
}

邏輯

設定必要的 flags 和初始值

var previous: ListNode? = nil
var current = listNode
var next: ListNode? = nil

previousnext 是在反轉替換過程中用來暫存節點的 flags

Routine

透過走訪和指標替換的邏輯,來達到反轉 linked list 的目的

while current != nil {
    next = current?.next
    current?.next = previous
    previous = current
    current = next
}

當 current 為空值的時候

  • 這個 linked list 本來就是空的
  • 已經走訪完這個 linked list

就可以結束 routines 。

初始狀態

以這個 linked list 為例

C
1 -> 2 -> 3 -> 4

第一 routine

更新 next ,避免接下來 current 換掉 next node 的時候失去參照

// next = current?.next

C    N
1 -> 2 -> 3 -> 4

更新 current?.next ,指向 previous 。
在第一步驟 P 是空值,因此是指向 nil

// current?.next = previous

C    N
1    2 -> 3 -> 4
|  
+--> nil
     P

結束替換,將 previous 換到 current

// previous = current

P
C    N
1    2 -> 3 -> 4
|  
+--> nil

current 換到 next 的位置準備下一次的替換

// current = next

     C
P    N
1    2 -> 3 -> 4
|  
+--> nil

結束 Routines

從上面的圖可以發現 previous 在結束每次 routine 之後都會指向反轉後 linked list 的節點
因此可以直接回傳 previous 做為結果

return previous

分析

時間複雜度 -> O(n)

線性複雜度,因為每一個節點只有走訪過一次

空間複雜度 -> O(1)

我們只有宣告 flag 用途的變數,也沒有宣告新的物件因此是常數複雜度 O(1)

ListNode 的資料結構

基本的 singly linked list 的節點,有兩個 properties :

  • value 用來存值
  • next 用來指向下一個節點

實作和 initializer 參照 LeetCode 。
另外加上方便 debug 用的 helper Method

class ListNode {
    var value: Int
    var next: ListNode?

    init() {
        self.value = 0
        self.next = nil
    }

    init(_ value: Int) { 
        self.value = value
        self.next = nil
    }

    init(_ value: Int, _ next: ListNode?) {
        self.value = value
        self.next = next
    }

    // MARK: - Helper Method

    var array: [Int] {
        var result = [Int]()
        var current: ListNode? = self
        while current != nil {
            result.append(dummy!.value)
            current = current?.next
        }
        return result
    }
}

Discussion