Problem Description
Given the head of a linked list, return the list after sorting it in ascending order.
Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)?
Examples
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: []
Python Solution
def sortList(head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
# Find middle
slow = fast = head
prev = None
while fast and fast.next:
fast = fast.next.next
prev = slow
slow = slow.next
prev.next = None
# Recursively sort both halves
left = sortList(head)
right = sortList(slow)
# Merge sorted halves
dummy = ListNode(0)
curr = dummy
while left and right:
if left.val <= right.val:
curr.next = left
left = left.next
else:
curr.next = right
right = right.next
curr = curr.next
curr.next = left or right
return dummy.next
Java Solution
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
// Find middle
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
prev = slow;
slow = slow.next;
}
prev.next = null;
// Recursively sort both halves
ListNode left = sortList(head);
ListNode right = sortList(slow);
// Merge sorted halves
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
while (left != null && right != null) {
if (left.val <= right.val) {
curr.next = left;
left = left.next;
} else {
curr.next = right;
right = right.next;
}
curr = curr.next;
}
curr.next = left != null ? left : right;
return dummy.next;
}
}
C++ Solution
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (!head || !head->next) {
return head;
}
// Find middle
ListNode* slow = head;
ListNode* fast = head;
ListNode* prev = nullptr;
while (fast && fast->next) {
fast = fast->next->next;
prev = slow;
slow = slow->next;
}
prev->next = nullptr;
// Recursively sort both halves
ListNode* left = sortList(head);
ListNode* right = sortList(slow);
// Merge sorted halves
ListNode dummy(0);
ListNode* curr = &dummy;
while (left && right) {
if (left->val <= right->val) {
curr->next = left;
left = left->next;
} else {
curr->next = right;
right = right->next;
}
curr = curr->next;
}
curr->next = left ? left : right;
return dummy.next;
}
};
JavaScript Solution
/**
* @param {ListNode} head
* @return {ListNode}
*/
var sortList = function(head) {
if (!head || !head.next) {
return head;
}
// Find middle
let slow = head;
let fast = head;
let prev = null;
while (fast && fast.next) {
fast = fast.next.next;
prev = slow;
slow = slow.next;
}
prev.next = null;
// Recursively sort both halves
const left = sortList(head);
const right = sortList(slow);
// Merge sorted halves
const dummy = new ListNode(0);
let curr = dummy;
while (left && right) {
if (left.val <= right.val) {
curr.next = left;
left = left.next;
} else {
curr.next = right;
right = right.next;
}
curr = curr.next;
}
curr.next = left || right;
return dummy.next;
};
C# Solution
public class Solution {
public ListNode SortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
// Find middle
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
prev = slow;
slow = slow.next;
}
prev.next = null;
// Recursively sort both halves
ListNode left = SortList(head);
ListNode right = SortList(slow);
// Merge sorted halves
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
while (left != null && right != null) {
if (left.val <= right.val) {
curr.next = left;
left = left.next;
} else {
curr.next = right;
right = right.next;
}
curr = curr.next;
}
curr.next = left != null ? left : right;
return dummy.next;
}
}
Complexity Analysis
- Time Complexity: O(n log n) where n is the number of nodes in the linked list
- Space Complexity: O(log n) due to recursion stack
Solution Explanation
This solution implements merge sort on a linked list:
- Key concept:
- Divide and conquer
- Merge sort
- Two-pointer technique
- Algorithm steps:
- Find middle point
- Split into halves
- Sort recursively
- Merge sorted lists
Key points:
- Optimal time complexity
- Recursive approach
- Stable sorting
- Middle finding