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 on the following form:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
You may not modify the values in the list's nodes. Only nodes themselves may be changed.
Example 1:
Input: head = [1,2,3,4] Output: [1,4,2,3]
Example 2:
Input: head = [1,2,3,4,5] Output: [1,5,2,4,3]
Constraints:
[1, 5 * 104]
.1 <= Node.val <= 1000
This problem asks us to reorder a singly linked list in a specific pattern. The approach uses three main steps:
Find the Middle: We use two pointers, slow
and fast
, to find the middle of the linked list. The slow
pointer moves one step at a time, while the fast
pointer moves two steps at a time. When the fast
pointer reaches the end (or null
), the slow
pointer will be at (or near) the middle.
Reverse the Second Half: We reverse the second half of the linked list (from slow.next
onwards). This is a standard linked list reversal technique. We iterate through the second half, changing each node's next
pointer to point to the previous node.
Merge the Two Halves: We merge the first half and the reversed second half by interleaving their nodes. We iterate through both halves simultaneously, alternating between adding a node from the first half and a node from the reversed second half to the reordered list.
slow
and fast
pointer technique iterates through the list once, taking O(n) time, where n is the number of nodes in the list.Therefore, the overall time complexity of the algorithm is O(n).
The algorithm uses a constant amount of extra space for pointers (slow
, fast
, cur
, pre
, t
). It does not use any auxiliary data structures that grow with the size of the input. Thus, the space complexity is O(1).
# 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:
#Find the middle
fast = slow = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
#Reverse the second half
cur = slow.next
slow.next = None #Separate the two halves
pre = None
while cur:
temp = cur.next #Store the next node
cur.next = pre #Reverse the link
pre = cur #Move to the next node to reverse
cur = temp #Move to the next node to process
#Merge the two halves
cur = head
while pre:
temp = pre.next #Store the next node of the reversed list
pre.next = cur.next #Link the reversed node to the next of the first half
cur.next = pre #Link the first half node to the reversed node
cur = cur.next #Move to the next node in the first half
pre = temp #Move to the next node in the reversed half
The other language implementations follow the same three-step process, differing only in syntax and data structure handling specific to each language. The core logic remains consistent.