Merge sort a linked list

problem [https://leetcode.com/problems/sort-list/ 148. Sort List].

This problem is based on the simpler problem: Merge two sorted linked lists.

Problem description
Given the  of a linked list, return the list after sorting it in ascending order.


 * Follow up
 * Can you sort the linked list in O(n log n) time and O(1) memory (i.e. constant space)?


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


 * Example 2
 * Input: head = [-1,5,3,4,0]
 * Output: [-1,0,3,4,5]


 * Example 3
 * Input: head = []
 * Output: []


 * Constraints
 * The number of nodes in the list is in the range.

Approach 1: top-down (O(n log n) time complexity, O(log n) space complexity)
The top-down approach is as follows:
 * 1) Find the midpoint of the linked list.
 * 2) * If there are even number of nodes, then find the first of the middle element.
 * 3) Break the linked list after the midpoint.
 * 4) * Use two pointers  and   to store the heads of the two halves.
 * 5) Recursively merge sort the two halves.
 * 6) Merge the two sorted halves recursively.

Time complexity

 * 1) The splitting phase
 * 2) * Finding the middle point takes O(m) time for m nodes.
 * 3) * The total time for splitting n nodes is $$T(n)_{\text{split}} = T(\frac{n}{2})_{\text{split}} + 2 \cdot T(\frac{n}{4})_{\text{split}} + 4 \cdot T(\frac{n}{8})_{\text{split}} + \dots + \frac{n}{2} \cdot T(1)_{\text{split}}$$$$= O(\frac{n}{2} \cdot \log_{2}{\frac{n}{2}})$$.
 * 4) The merging phase
 * 5) * Merging k modes takes O(k) time.
 * 6) * The total time for merging n nodes is $$T(n)_{\text{merge}} = 2 \cdot T(\frac{n}{2})_{\text{merge}} + 4 \cdot T(\frac{n}{4})_{\text{merge}} + \dots + n \cdot T(1)_{\text{merge}}$$$$= O(n \log_{2}{n})$$.

Summing them up gives the total time complexity of O(n log n).

Space complexity

 * Stack
 * During each recursive call we need to maintain the two pointers  and  . Since the recursion is executed depth-first, this results in the space complexity of O(log n).


 * Heap
 * We did not allocate any new objects. So the space complexity on heap is O(1).

The total time complexity is O(log n).

Approach 2: bottom-up (O(n log n) time complexity, O(1) space complexity)
Noting that the top-bottom approach takes O(log n) space complexity due to the recursion calls, we need to think about if we can use an iterative approach to merge the sorted lists of sizes 1, 2, 4, 8, … so that we can achieve the follow-up requirement of O(1) space complexity.

Our bottom-up approach is as follows:
 * 1) Interpret the linked list as a collection of size-1 linked lists, with each small linked list considered sorted. (Linked lists of size 0 or 1 are automatically considered sorted)
 * 2) Iteratively split and merge small sorted linked lists by groups of 2 (= 1 + 1), 4 (= 2 + 2), 8 (= 4 + 4), …, from left to right, and reorder the nodes in the whole linked list in-place.
 * 3) Repeat the iterations above until the whole linked list is merge-sorted completely.

Split and merge
For small sizes of k = 1, 2, 4, 8, … (all are powers of 2), what we need to do are:
 * 1) Dummy head
 * 2) Create a dummy head pointer.
 * 3) Set the initial merged tail to the dummy head.
 * 4) Create a   pointer to scan the linked list from left to right. Initialize it to the head of the whole linked list.
 * 5) The splitting phase
 * 6) From the position of the   pointer, find the midpoint of the segment from the head of the list with size k⋅2. The midpoint becomes the tail of the first half (with size k) of this segment.
 * 7) Now the head of the second half of this segment is right after the midpoint.
 * 8) Break the linked list after the midpoint (set its    pointer to  ).
 * 9) Find the tail of the second half. Then the node right after the tail is the head of the next sub-list.
 * 10) Again, break the linked list after the tail (set its    pointer to  ), so that the second half also has size k.
 * 11) The merging phase
 * 12) Merge the first k⋅2 elements from the two lists after the split. Record the head and tail of this merged list.
 * 13) Set the previous merged tail's   pointer to the head of this merged list.
 * 14) Set the merged tail to the tail of this merged list.
 * 15) Advance the   pointer to the head of the next sub-list.
 * 16) Repeat the split-and-merge process from left to right of the linked list, until all the elements are processed in groups of k, i.e. the   pointer becomes.

After every left-to-right processing of the linked list, we multiply k by 2 and repeat the split-and-merge process, until k &ge; the size of the whole linked list.

Time complexity

 * 1) For n total nodes, we use k = 1, 2, 4, 8, …, until k &ge; n. So the number of possible k ' s are $$\log_{2}{n}$$.
 * 2) For each k that is used, each split-and-merge process takes O(n) time, since each node is processed twice:
 * 3) Once for finding the breakpoints and splitting the linked list into smaller sub-lists of size k;
 * 4) Once for merging the small sub-lists of size k into sub-lists of size k⋅2.

So the total time complexity is O(n log n).

Space complexity

 * Stack
 * For each iteration we only used the same, fixed set of helper pointers. So the space complexity on stack is O(1).


 * Heap
 * We only have allocated one instance of the  class and   class. Also the dummy nodes take a fixed amount of space. So the heap space complexity is O(1).

The total space complexity is O(1).