You are given the head of a singly linked list, sort the list using insertion sort, and return the sorted list's head.
The steps of the insertion sort algorithm:
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]Constraints:
1 <= The length of the list <= 5000.-5000 <= Node.val <= 5000Before attempting this problem, you should be comfortable with:
Since sorting a linked list in place can be tricky, we can simplify the problem by extracting all the values into an array. Once in array form, we can use any standard sorting algorithm. After sorting, we traverse the linked list again and overwrite each node's value with the sorted values in order.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
arr = []
cur = head
while cur:
arr.append(cur.val)
cur = cur.next
arr.sort()
cur = head
for val in arr:
cur.val = val
cur = cur.next
return headThis approach mimics insertion sort by comparing values rather than rearranging node pointers. For each node, we scan from the head to find any earlier node with a larger value and swap values. This bubbles smaller values toward the front, eventually producing a sorted list. While simpler to implement than pointer manipulation, it still requires O(n^2) comparisons.
cur = head.next).cur, traverse from head to cur:tmp has a value greater than cur.val, swap their values.cur to the next node and repeat.head of the list.# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head.next
while cur:
tmp = head
while tmp != cur:
if tmp.val > cur.val:
tmp.val, cur.val = cur.val, tmp.val
tmp = tmp.next
cur = cur.next
return headThis is the classic insertion sort adapted for linked lists. Instead of swapping values, we physically remove a node and reinsert it at the correct position in the already sorted portion. A dummy node simplifies insertions at the head. If the current node is already in order relative to the previous node, we just advance. Otherwise, we unlink it and search from the beginning for the right spot.
dummy node pointing to the head to handle edge cases.prev as the last node of the sorted portion and cur as the node being examined.cur.val >= prev.val, the node is in place; advance both pointers.dummy:cur from its current position.cur after the found position.cur to prev.next to continue.dummy.next.# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0, head)
prev, cur = head, head.next
while cur:
if cur.val >= prev.val:
prev, cur = cur, cur.next
continue
tmp = dummy
while cur.val > tmp.next.val:
tmp = tmp.next
prev.next = cur.next
cur.next = tmp.next
tmp.next = cur
cur = prev.next
return dummy.nextWhen removing a node from its current position to reinsert it elsewhere, failing to save cur.next before modifying pointers causes the reference to the next node to be lost. Always store the next node in a temporary variable before performing any pointer manipulation.
When the smallest element is found later in the list and needs to become the new head, not using a dummy node makes head updates awkward and error-prone. A dummy node pointing to the head simplifies insertions at the beginning by providing a consistent previous node.
After inserting a node into its correct sorted position, the prev pointer should not advance because the node that was after cur is now directly after prev. Advancing prev would skip a node. Only cur should be updated to prev.next to continue with the next unsorted element.