0148. Sort List

Medium | Linked List + MergeSort | 172 ms (98.38%), 45.6 MB (95.85%)

Source: LeetCode - Sort List GitHub: Solution / Performance

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

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

To meet O(1) memory complexity, we need to do Merge Sort by splitting the linked list into multiple segments bottom-up.

Before splitting, we need to get the length of the input linked list.

Then split the linked list bottom-up by starting with size = 1, this size will grow two times of itself in each iteration by size *= 2 until size >= length.

For the process of splitting and merging, we need to maintain two pointers:

  1. splitHead is to check whether the splitting process needs to end or not.

  2. mergeHead is for merging two split linked lists so that we can maintain relative order for the next splitting process.

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        #  (base case)
        if not head or not head.next: return head
        
        # ==================================================
        #  Linked List + Merge Sort           (Iterative)  =
        # ==================================================
        # time  : O(nlog(n))
        # space : O(1)
        
        length = self.getSize(head)
        ret, size = ListNode(0, head), 1
        
        while size < length:
            splitHead, mergeHead = ret.next, ret
            
            while splitHead:
                left  = splitHead
                right = self.split(size, left)
                
                splitHead = self.split(size, right)
                mergeHead = self.merge(left, right, mergeHead)
            
            size *= 2
        
        return ret.next
        
    def getSize(self, node: ListNode) -> int:
        size, tmp = 0, node
        while tmp: size, tmp = size + 1, tmp.next
        return size
    
    def split(self, size: int, node: ListNode) -> ListNode:
        pre = None
        for i in range(size):
            if not node: break
            pre, node = node, node.next
        
        #  (break the link)
        if pre: pre.next = None
        return node
    
    def merge(self, left: ListNode, right: ListNode, head: ListNode) -> ListNode:
        while left and right:
            if left.val <= right.val: head.next, left = left, left.next
            else: head.next, right = right, right.next
                
            head = head.next
        
        head.next = left if left else right
        while head.next: head = head.next
        return head

Last updated