Chapter 5: Linked List Challenges

Challenge 1: Create a function that prints out the elements of a linked list in reverse order

  • 思路

    • 利用遞迴的方式來建立call stack, 然後最早被呼叫的print會最晚被執行到。

func printInReverse<T>(_ list: LinkedList<T>) {
    printInReverse(list.head)
}

private func printInReverse<T>(_ node: Node<T>?) {
    // 當node = nil, 表示已經到list末端
    guard let node = node else { return }
    // 技巧:利用遞迴呼叫來建立call stack
    printInReverse(node.next)
    // 最早被呼叫的print會最晚被執行
    print(node.value)
}

Challenge 2: Create a function that returns the middle node of a linked list

  • 思路

    • 利用快慢兩個指針

    • 快指針前速度是慢指針兩倍,當快指針到末端時,慢指針剛好指向中間。

func getMiddle<T>(_ list: LinkedList<T>) -> Node<T>? {
  // 利用快慢兩個指針
    var slow = list.head
    var fast = list.head

    while let nextFast = fast?.next {
        // 快指針前速度是慢指針兩倍
        // 快指針呼叫兩次next
        fast = nextFast.next
        slow = slow?.next
    }

    return slow
}

Challenge 3: Create a function that reverses a linked list

  • 思路

    • 利用三個指針prv, cur, next,來進行反轉動作。

    • 投結點要獨立出來處理。

  mutating func reverse() {
    tail = head
    var prev = head
    var current = head?.next
    // 先處理頭節點
    prev?.next = nil

    while current != nil {
        // 先利用next指針紀錄current的next
        let next = current?.next
        // 進行反轉
        current?.next = prev
        // 將pre, cur繼續往前移動
        prev = current
        current = next
    }

    head = prev
  }

Challenge 4: Create a function that takes two sorted linked lists and merges them into a single sorted linked list

  • 思路

    • newHead指向當前兩個list中最小的node

    • tail指針的移動來進行合併list

func mergeSorted<T: Comparable>(_ left: LinkedList<T>,
                                _ right: LinkedList<T>) -> LinkedList<T> {
    // 先確保left & right都有數值
    guard !left.isEmpty else {
        return right
    }

    guard !right.isEmpty else {
        return left
    }

    var newHead: Node<T>?
    var tail: Node<T>?
    var currentLeft = left.head
    var currentRight = right.head

    // 找出當前最小的node
    if let leftNode = currentLeft, let rightNode = currentRight {
        if leftNode.value < rightNode.value {
            newHead = leftNode
            currentLeft = leftNode.next
        } else {
            newHead = rightNode
            currentRight = rightNode.next
        }
        tail = newHead
    }

    // 利用tail指針的next來合併list
    while let leftNode = currentLeft, let rightNode = currentRight  {
        if leftNode.value < rightNode.value {
            tail?.next = leftNode
            currentLeft = leftNode.next
        } else {
            tail?.next = rightNode
            currentRight = rightNode.next
        }

        tail = tail?.next
    }

    // 當left list還有剩
    if let leftNode = currentLeft {
        tail?.next = leftNode
    }

    // 當right list還有剩
    if let rightNode = currentRight {
        tail?.next = rightNode
    }

    // 產生新的list
    var list = LinkedList<T>()
    list.head = newHead
    list.tail = {
        while let next = tail?.next {
            tail = next
        }
        return tail
    }()

  return list
}

Challenge 5: Create a function that removes all occurrences of a specific element from a linked list

  • 思路

    • 一樣用兩根指針pre, cur不斷搜尋

    • 當遇到需要刪除的值就是把pre的next跳過cur, 直接指向cur的next

extension LinkedList where Value: Equatable {

  mutating func removeAll(_ value: Value) {

    // Edge case: 當被刪的節點是head
    while let head = head, head.value == value {
        self.head = head.next
    }

    // 斷開節點
    var prev = head
    var current = head?.next
    while let currentNode = current {
        guard currentNode.value != value else {
            // 刪除current節點
            prev?.next = currentNode.next
            current = prev?.next
            continue
        }
        prev = current
        current = current?.next
    }
    tail = prev
  }
}

Last updated

Was this helpful?