The Problem
You are given the head of a singly linked list. The list can be represented as:
L0 → L1 → … → Ln - 1 → Ln
Reorder the list to be in the following form:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
You may not modify the values in the list’s nodes. Only the nodes themselves may be changed.
Examples
Input: head = [1,2,3,4]
Output: [1,4,2,3]
Input: head = [1,2,3,4,5]
Output: [1,5,2,4,3]
Constraints
- The number of nodes in the list is in the range [1, 5 * 10⁴].
- 1 <= Node.val <= 1000
Brute Force Solution
func reorderList(_ head: ListNode?) {
guard let head = head else {
return
}
var nodes: [ListNode] = []
var curr: ListNode? = head
while curr != nil {
nodes.append(curr!)
curr = curr!.next
}
var l = 0
var r = nodes.count - 1
while l < r {
nodes[l].next = nodes[r]
l += 1
if l >= r {
break
}
nodes[r].next = nodes[l]
r -= 1
}
nodes[l].next = nil
}
Explanation
We can solve this problem using additional memory and the two-pointer technique.
When we iterate over all nodes in head
and add them to an array, we can precisely know the index of each value. By knowing this, we can reorder the list by updating the next
pointer. For example, Input: head = [1,2,3,4]
will look like this: 1 -> 4 -> 2 -> 3 -> nil
.
Time/Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(n)
Slow/Fast Pointers Solution
func reorderList(_ head: ListNode?) {
guard let head = head else {
return
}
var slow: ListNode? = head
var fast = head.next
// Find middle
while fast != nil && fast?.next != nil {
slow = slow?.next
fast = fast?.next?.next
}
var second = slow?.next
slow?.next = nil
var prev: ListNode?
// Reverse second half
while second != nil {
let tmp = second?.next
second?.next = prev
prev = second
second = tmp
}
var first: ListNode? = head
second = prev
// Merge two halves
while second != nil {
let tmp1 = first?.next
let tmp2 = second?.next
first?.next = second
second?.next = tmp1
first = tmp1
second = tmp2
}
}
Explanation
To solve this problem in O(1) memory, we reverse the second half of the list.
To find the second half, we use slow
and fast
pointers by shifting the slow
pointer by one
step and the fast
pointer by two
steps. Finally, we merge the two halves to get the result.
Time/Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(1)