You are given the head of a singly linked-list.
The positions of a linked list of length = 7 for example, can intially be represented as:
[0, 1, 2, 3, 4, 5, 6]
Reorder the nodes of the linked list to be in the following order:
[0, 6, 1, 5, 2, 4, 3]
Notice that in the general case for a list of length = n the nodes are reordered to be in the following order:
[0, n-1, 1, n-2, 2, n-3, ...]
You may not modify the values in the list's nodes, but instead you must reorder the nodes themselves.
Example 1:
Input: head = [2,4,6,8]
Output: [2,8,4,6]Example 2:
Input: head = [2,4,6,8,10]
Output: [2,10,4,8,6]Constraints:
1 <= Length of the list <= 1000.1 <= Node.val <= 1000
You should aim for a solution with O(n) time and O(1) space, where n is the length of the given list.
A brute force solution would be to store the node values of the list in an array, reorder the values, and create a new list. Can you think of a better way? Perhaps you can try reordering the nodes directly in place, avoiding the use of extra space.
For example, consider the list [1, 2, 3, 4, 5]. To reorder the list, we connect the first and last nodes, then continue with the second and second-to-last nodes, and so on. Essentially, the list is split into two halves: the first half remains as is, and the second half is reversed and merged with the first half. For instance, [1, 2] will merge with the reversed [5, 4, 3]. Can you figure out a way to implement this reordering process? Maybe dividing the list into two halves could help.
We can divide the list into two halves using the fast and slow pointer approach, which helps identify the midpoint of the list. This allows us to split the list into two halves, with the heads labeled as l1 and l2. Next, we reverse the second half (l2). After these steps, we proceed to reorder the two lists by iterating through them node by node, updating the next pointers accordingly.
To reorder the linked list in the pattern:
L0 → Ln → L1 → L(n−1) → L2 → ...
A straightforward approach is to store all nodes in an array.
Once stored, we can easily access nodes from both the start and end using two pointers.
By alternately linking nodes from the front (i) and back (j), we can reshape the list in the required order.
i = 0 (start)j = len(nodes) - 1 (end)i < j:nodes[i].next to nodes[j]; increment i.i >= j, break the loop.nodes[j].next to nodes[i]; decrement j.nodes[i].next = None to terminate the list.# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
if not head:
return
nodes = []
cur = head
while cur:
nodes.append(cur)
cur = cur.next
i, j = 0, len(nodes) - 1
while i < j:
nodes[i].next = nodes[j]
i += 1
if i >= j:
break
nodes[j].next = nodes[i]
j -= 1
nodes[i].next = NoneThis recursive approach reorders the list by pairing nodes from the front and back during the recursion unwind phase.
The idea is:
cur) to the corresponding node from the front (root).root) step-by-step as recursion unwinds.Recursion naturally processes the list from back to front, making it convenient to match front and back nodes without using extra lists.
rec(root, cur):cur moves to the end of the list via recursion.root marks the current front node during unwinding.cur is None, return the front pointer (root).rec on cur.next to reach the tail.root meets or crosses cur, set cur.next = None to finish and stop further links.root.next.root.next → cur.cur.next → temp.temp) as the updated front pointer.rec(head, head.next).This reorders the list in place without extra storage.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
def rec(root: ListNode, cur: ListNode) -> ListNode:
if not cur:
return root
root = rec(root, cur.next)
if not root:
return None
tmp = None
if root == cur or root.next == cur:
cur.next = None
else:
tmp = root.next
root.next = cur
cur.next = tmp
return tmp
head = rec(head, head.next)To reorder the list into the pattern
L1 → Ln → L2 → Ln−1 → L3 → Ln−2 → ...,
we can break the problem into three simple steps:
Find the middle of the linked list using slow & fast pointers.
This splits the list into two halves.
Reverse the second half of the list.
Doing this makes it easy to merge nodes from the front and back alternately.
Merge the two halves one-by-one:
Take one node from the first half, then one from the reversed second half, and repeat.
This method is clean, intuitive, and uses only O(1) extra space.
Find the middle:
slow and fast pointers.fast reaches the end, slow will be at the midpoint.Reverse the second half:
slow.next.Merge the two lists:
This produces the desired reordered list in-place with no extra memory.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
slow, fast = head, head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next
second = slow.next
prev = slow.next = None
while second:
tmp = second.next
second.next = prev
prev = second
second = tmp
first, second = head, prev
while second:
tmp1, tmp2 = first.next, second.next
first.next = second
second.next = tmp1
first, second = tmp1, tmp2