Reorder list

LeetCode problem 143. Reorder List

## Problem description

Given a singly linked list *L*:

L
0

→

L
1

→

L
2

→
…
→

L
n

{\displaystyle L\_0 \rightarrow L\_1 \rightarrow L\_2 \rightarrow \ldots \rightarrow L\_n}

, reorder it to:

L
0

→

L
n

→

L
1

→

L

n
−
1

→

L
2

→

L

n
−
2

→
…

{\displaystyle L\_0 \rightarrow L\_n \rightarrow L\_1 \rightarrow L\_{n-1} \rightarrow L\_2 \rightarrow L\_{n-2} \rightarrow \ldots}

.

You may **not** modify the values in the list's nodes, only nodes itself may be changed.

Example 1
* Given 1 → 2 → 3 → 4, reorder it to 1 → 4 → 2 → 3.

Example 2

* Given 1 → 2 → 3 → 4 → 5, reorder it to 1 → 5 → 2 → 4 → 3.

## Analysis

We can break this problem into three subproblems:

1. Find the Middle of the linked list, and break the linked list after the midpoint.
	* Note: In case of the number of nodes is even, we break after the **first** node of the middle.
2. Reverse the second linked list.
3. Alternatingly merge the two linked lists.

### Complexity analysis

#### Time complexity

* Finding the midpoint takes O(n/2) time complexity.
* Reversing the second half takes O(n/2) time complexity.
* Merging takes O(n/2) time complexity.
* Add them up: the total time complexity = O(n/2) = **O(n)**.

#### Auxiliary space complexity

Stack
1. Finding midpoint: We used a slow and a fast pointer. The space complexity is O(1).
2. Reversing the second half: We have kept a `prev`, a `curr`, and a `next` pointer. The space complexity is O(1).
3. Merging: We have kept a dummy head and the three pointers `p1`, `p2`, and `pMerge`. The space complexity is O(1).

Total space complexity on stack is **O(1)**.

Heap
* We only have created the dummy node as the new object. So the total space complexity on heap is **O(1)**.

Add them up
We see that the total auxiliary space complexity is **O(1)**.

## Solution

### C++

```
/\*\*
 \* Definition for singly-linked list.
 \* struct ListNode {
 \* int val;
 \* ListNode \*next;
 \* ListNode() : val(0), next(nullptr) {}
 \* ListNode(int x) : val(x), next(nullptr) {}
 \* ListNode(int x, ListNode \*next) : val(x), next(next) {}
 \* };
 \*/
class Solution {
private:
 static ListNode\* findMid(ListNode\* head) {
 if ((head == nullptr) || (head->next == nullptr)) {
 return head;
 }

 ListNode \*slow = head, \*fast = head;
 while (fast != nullptr) {
 fast = fast->next;
 if (fast != nullptr) {
 fast = fast->next;
 }
 if (fast != nullptr) {
 slow = slow->next;
 }
 }
 return slow;
 }

 static ListNode\* reverse(ListNode\* head) {
 // iterative approach
 if ((head == nullptr) || (head->next == nullptr)) {
 return head;
 }

 ListNode \*prev = nullptr, \*curr = head;
 while (curr != nullptr) {
 ListNode \*next = curr->next;
 curr->next = prev;
 prev = curr;
 curr = next;
 }
 head = prev;
 return head;
 }

 static ListNode\* alternatingMerge(ListNode\* head1, ListNode\* head2) {
 // alternating merge

 if (head1 == nullptr) {
 return head2;
 }
 else if (head2 == nullptr) {
 return head1;
 }

 ListNode \*p1 = head1, \*p2 = head2;
 ListNode dummyHead(0), \*pMerge = &dummyHead;
 while (p1 != nullptr) {
 // in this problem, list 1 may have the same length as list 2
 // or one more node than list 2

 pMerge->next = new ListNode(p1->val);
 pMerge = pMerge->next;
 p1 = p1->next;

 if (p2 != nullptr) {
 pMerge->next = new ListNode(p2->val);
 pMerge = pMerge->next;
 p2 = p2->next;
 }
 }

 return dummyHead.next;
 }

public:
 void reorderList(ListNode\* head) {
 if ((head == nullptr) || (head->next == nullptr)) {
 return;
 }

 // find the midpoint
 ListNode \*mid = findMid(head);

 // break the list into two halves after the midpoint
 ListNode\* secondHead = mid->next;
 mid->next = nullptr;

 // reverse second half
 secondHead = reverse(secondHead);

 // alternatingly merge the two halves
 // use this workaround because we have to retain the original head
 ListNode\* subHead = head->next;
 subHead = alternatingMerge(secondHead, subHead);
 head->next = subHead;
 return;
 }
};

```

### Java

```
/\*\*
 \* Definition for singly-linked list.
 \* public class ListNode {
 \* int val;
 \* ListNode next;
 \* ListNode() {}
 \* ListNode(int val) { this.val = val; }
 \* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 \* }
 \*/
class Solution {
 private static ListNode findMid(ListNode head) {
 if ((head == null) || (head.next == null)) {
 return head;
 }

 ListNode slow = head, fast = head;
 while (fast != null) {
 fast = fast.next;
 if (fast != null) {
 fast = fast.next;
 }
 if (fast != null) {
 slow = slow.next;
 }
 }
 return slow;
 }

 private static ListNode reverse(ListNode head) {
 // iterative approach
 if ((head == null) || (head.next == null)) {
 return head;
 }

 ListNode prev = null, curr = head;
 while (curr != null) {
 ListNode next = curr.next;
 curr.next = prev;
 prev = curr;
 curr = next;
 }
 head = prev;
 return head;
 }

 private static ListNode alternatingMerge(ListNode head1, ListNode head2) {
 // alternating merge

 if (head1 == null) {
 return head2;
 }
 else if (head2 == null) {
 return head1;
 }

 ListNode p1 = head1, p2 = head2;
 ListNode dummyHead = new ListNode(0), pMerge = dummyHead;
 while (p1 != null) {
 // in this problem, list 1 may have the same length as list 2
 // or one more node than list 2

 pMerge.next = new ListNode(p1.val);
 pMerge = pMerge.next;
 p1 = p1.next;

 if (p2 != null) {
 pMerge.next = new ListNode(p2.val);
 pMerge = pMerge.next;
 p2 = p2.next;
 }
 }

 return dummyHead.next;
 }

 public void reorderList(ListNode head) {
 if ((head == null) || (head.next == null)) {
 return;
 }

 // find the midpoint
 ListNode mid = findMid(head);

 // break the list into two halves after the midpoint
 ListNode secondHead = mid.next;
 mid.next = null;

 // reverse second half
 secondHead = reverse(secondHead);

 // alternatingly merge the two halves
 // use this workaround because we have to retain the original head
 ListNode subHead = head.next;
 subHead = alternatingMerge(secondHead, subHead);
 head.next = subHead;
 return;
 }
}

```

## Notes

* In this problem we are NOT allowed to generate a new head to replace head (because the return type is `void`). When doing the alternating merging step, a workaround is to get the subhead (the next node following the head of list 1), merge the second head with subhead, and set `head->next = subHead;`.