Post

LC 143 - Reorder List

LC 143 - Reorder List

Question

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:

1
2
Input: head = [1,2,3,4]
Output: [1,4,2,3]

Example 2:

1
2
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 * 104].
  • 1 <= Node.val <= 1000

Question here and solution here

Solution

concept

The most straight forward way to do is first store them in a list, and then use two-pointers to reconnect the linked list.

Alternative we can first find out the segments of the linked list such that they are more or less equal. We can do this by having a fast and slow pointer (Note that the fast pointer starts at head.next while slow pointer start at head.)

For both the case of even or odd number of nodes, the 2nd segment starts at slow.next We then reverse the second segment of the linked list, this allow us to traverse the 2nd part of the linked list in reverse. Finally we will use a two pointers to traverse from the two ends.

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 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:
        """
        Do not return anything, modify head in-place instead.
        
        two-pointer with list to store the node first
        """
        nodes = []
        cur = head

        while cur:
            nodes.append(cur)
            cur = cur.next

        l, r = 0, len(nodes) - 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 = None
        
class NeetSolution:
    def reorderList(self, head: Optional[ListNode]) -> None:
        """
        Do not return anything, modify head in-place instead.
        time complexity: O(n)
        space complexity: O(1)
        """
        # determine first and second segment of linked list
        # slow.next will be the beginning of 2nd segment
        slow, fast = head, head.next
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

        # reverse 2nd segment
        second = slow.next
        # split the linked list to 2 segment
        slow.next = None
        # previous nodes default
        prev = None
        # iterate the (potential) shorter segment
        while second:
            # before break the link, cache first
            tmp = second.next
            # now point to prev
            second.next = prev
            # move prev to curr (i.e. second)
            prev = second
            # move curr (i.e. second) to (original) next
            second = tmp

        # merge
        # original second will be None
        # but prev will be the last node of the original 2nd seg, now becomes the new head of the reversed linked list
        first, second = head, prev
        while second:
            # cache before breaking the next to point to new nodes
            tmp1, tmp2 = first.next, second.next
            first.next = second
            second.next = tmp1
            first = tmp1
            second = tmp2

Complexity

time: $O(n)$
space: $O(n)$ if use two pointer and list, $O(1)$ if use the reverse and merge method

This post is licensed under CC BY 4.0 by the author.