👨‍💻
LeetCode
  • Overview
  • Mixed / Design
    • Two Sum (4 Qs)
      • 0001. Two Sum
      • 0167. Two Sum II - Input array is sorted
      • 0170. Two Sum III - Data structure design
      • 0653. Two Sum IV - Input is a BST
    • 0015. 3Sum
    • 0208. Implement Trie (Prefix Tree)
  • String
    • 0014. Longest Common Prefix
    • 0028. Implement strStr()
    • 0344. Reverse String
    • 0151. Reverse Words in a String
    • 0557. Reverse Words in a String III
    • 0067. Add Binary
    • 0415. Add Strings
    • 0038. Count and Say
    • 0394. Decode String
    • 0953. Verifying an Alien Dictionary
    • 0020. Valid Parentheses
  • Linked List
    • 0002. Add Two Numbers
    • 0445. Add Two Numbers II
    • 0021. Merge Two Sorted Lists
    • 0023. Merge k Sorted Lists
    • 0206. Reverse Linked List
    • 0019. Remove Nth Node From End of List
  • Tree
    • 0098. Validate BST
    • 0100. Same Tree
    • 0101. Symmetric Tree
    • 0226. Invert Binary Tree
    • 0110. Balanced Binary Tree
    • 0250. Count Univalue Subtrees
    • 0654. Maximum Binary Tree
    • Binary Tree Traversal (7 Qs)
      • 0144. Preorder Traversal
      • 0145. Postorder Traversal
      • 0094. Inorder Traversal
      • 0102. Level Order Traversal
      • 0104. Maximum Depth
      • 0111. Minimum Depth
      • 1302. Deepest Leaves Sum
      • 0993. Cousins in Binary Tree
    • N-ary Tree Traversal (4 Qs)
      • 0589. Preorder Traversal
      • 0590. Postorder Traversal
      • 0429. Level Order Traversal
      • 0559. Maximum Depth
    • Convert to BST (2 Qs)
      • 0108. Convert Sorted Array to Binary Search Tree
      • 0109. Convert Sorted List to Binary Search Tree
  • Binary Search
    • 0704. Binary Search
    • 0035. Search Insert Position
    • 0278. First Bad Version
    • 0367. Valid Perfect Square
    • 0069. Sqrt(x)
    • 0875. Koko Eating Bananas
    • 1011. Capacity To Ship Packages Within D Days
    • 0410. Split Array Largest Sum
    • 0004. Median of Two Sorted Arrays
  • Two Pointer
    • 0075. Sort Colors
    • 0088. Merge Sorted Array
    • 0283. Move Zeroes
    • 0125. Valid Palindrome
    • 0011. Container With Most Water
    • 0026. Remove Duplicates from Sorted Array
  • Sliding Window
    • 0003. Longest Substring Without Repeating Characters
  • Sorting
    • 0148. Sort List
    • 0912. Sort an Array
    • 0215. Kth Largest in Array
  • Dynamic Programming
    • 0509. Fibonacci Number
    • 1137. N-th Tribonacci Number
    • 0055. Jump Game
    • 0053. Maximum Subarray
    • 0022. Generate Parentheses
    • 0005. Longest Palindromic Substring
    • 0072. Edit Distance
    • Buy and Sell Stock (6 Qs)
      • 0122. Best Time to Buy and Sell Stock II
      • 0714. Best Time to Buy and Sell Stock with Transaction Fee
      • 0121. Best Time to Buy and Sell Stock
      • 0309. Best Time to Buy and Sell Stock with Cooldown
      • 0123. Best Time to Buy and Sell Stock III
      • 0188. Best Time to Buy and Sell Stock IV
  • DFS / BFS
    • 0200. Number of Islands
  • Math
    • 0007. Reverse Integer
    • 0009. Palindrome Number
Powered by GitBook
On this page

Was this helpful?

  1. Sorting

0148. Sort List

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

Previous0003. Longest Substring Without Repeating CharactersNext0912. Sort an Array

Last updated 3 years ago

Was this helpful?

Source: GitHub:

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)?

Constraints:

  • The number of nodes in the list is in the range [0, 5 * 10^4].

  • -10^5 <= Node.val <= 10^5

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

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

Input: head = []
Output: []

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
class Solution {
    /**
     * @time  : O(nlog(n))
     * @space : O(1)
     */
    
    public ListNode sortList(ListNode head) {
        /* base case */
        if(head == null || head.next == null) return head;
        
        int len = getLen(head);
        
        int size = 1;
        ListNode ret = new ListNode(0, head);
        
        while(size < len) {
            ListNode splitHead = ret.next, mergeHead = ret;
            while(splitHead != null) {
                ListNode left  = splitHead;
                ListNode right = split(size, left);
                
                splitHead = split(size, right);
                mergeHead = merge(left, right, mergeHead);
            }
            
            size *= 2;
        }
        
        return ret.next;
    }
    
    public int getLen(ListNode head) {
        int len = 0;
        ListNode cur = head;
        while(cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }
    
    public ListNode split(int size, ListNode node) {
        ListNode pre = null;
        for(int i=0 ; i<size ; i++) {
            if(node == null) break; 
            pre = node;
            node = node.next;
        }
        /* break the link */
        if(pre != null) pre.next = null;
        return node;
    }
    
    public ListNode merge(ListNode left, ListNode right, ListNode head) {
        while(left != null && right != null) {
            if(left.val <= right.val) {
                head.next = left;
                left = left.next;
            } else {
                head.next = right;
                right = right.next;
            }
            head = head.next;
        }
        head.next = (left != null) ? left : right;
        while(head.next != null) head = head.next;
        return head;
    }
}
LeetCode - Sort List
Solution / Performance