Split Linked List in Parts
Initialize total_nodes and current pointer
Set total_nodes to 0 and current pointer to head of the list to start counting nodes.
total_nodes = 0
current = headCount first node
Increment total_nodes to 1 because current points to the first node with value 1. Move current to next node.
total_nodes += 1
current = current.nextCount second node
Increment total_nodes to 2 as current points to node with value 2. Move current to next node.
total_nodes += 1
current = current.nextCount third node
Increment total_nodes to 3 as current points to node with value 3. Move current to next node which is null, ending count.
total_nodes += 1
current = current.nextCalculate part size and remainder
Calculate base part size as total_nodes // k = 3 // 5 = 0 and remainder as total_nodes % k = 3 % 5 = 3.
part_size = total_nodes // k
remainder = total_nodes % kInitialize parts array and reset current pointer
Create an array parts of size k with all None and reset current pointer to head to start splitting.
parts = [None] * k
current = headAssign first part head and calculate size
Set parts[0] to current node (1). Calculate size as part_size + 1 because remainder > 0, so size = 1. Decrement remainder to 2.
parts[i] = current
size = part_size + (1 if remainder > 0 else 0)
if remainder > 0:
remainder -= 1Traverse to end of first part
Since size is 1, no inner loop traversal needed. Current points to node 1, which is the end of this part.
for j in range(size - 1):
if current:
current = current.nextBreak link to separate first part
Save next_part as current.next (node 2). Break link by setting current.next to None. Move current pointer to next_part (node 2).
if current:
next_part = current.next
current.next = None
current = next_partAssign second part head and calculate size
Set parts[1] to current node (2). Calculate size as part_size + 1 because remainder > 0, so size = 1. Decrement remainder to 1.
parts[i] = current
size = part_size + (1 if remainder > 0 else 0)
if remainder > 0:
remainder -= 1Traverse to end of second part
Since size is 1, no inner loop traversal needed. Current points to node 2, end of this part.
for j in range(size - 1):
if current:
current = current.nextBreak link to separate second part
Save next_part as current.next (node 3). Break link by setting current.next to None. Move current pointer to next_part (node 3).
if current:
next_part = current.next
current.next = None
current = next_partAssign third part head and calculate size
Set parts[2] to current node (3). Calculate size as part_size + 1 because remainder > 0, so size = 1. Decrement remainder to 0.
parts[i] = current
size = part_size + (1 if remainder > 0 else 0)
if remainder > 0:
remainder -= 1Traverse to end of third part
Since size is 1, no inner loop traversal needed. Current points to node 3, end of this part.
for j in range(size - 1):
if current:
current = current.nextBreak link to separate third part
Save next_part as current.next (null). Break link by setting current.next to None (already None). Move current pointer to next_part (null).
if current:
next_part = current.next
current.next = None
current = next_partAssign empty fourth part
Set parts[3] to current which is null, indicating an empty part.
parts[i] = currentAssign empty fifth part
Set parts[4] to current which is null, indicating an empty part.
parts[i] = currentReturn parts array as result
Return the array parts containing heads of each split part, including empty parts represented by None.
return partsclass ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def splitListToParts(head, k):
total_nodes = 0 # STEP 1
current = head # STEP 1
while current: # STEP 2-4 loop
total_nodes += 1 # STEP 2-4
current = current.next # STEP 2-4
part_size = total_nodes // k # STEP 5
remainder = total_nodes % k # STEP 5
parts = [None] * k # STEP 6
current = head # STEP 6
for i in range(k): # STEP 7-17 loop
parts[i] = current # STEP 7,10,13,16,17
size = part_size + (1 if remainder > 0 else 0) # STEP 7,10,13
if remainder > 0: # STEP 7,10,13
remainder -= 1 # STEP 7,10,13
for j in range(size - 1): # STEP 8,11,14
if current:
current = current.next
if current: # STEP 9,12,15
next_part = current.next
current.next = None
current = next_part
return parts # STEP 18
Key Takeaways
This counting step is crucial and often overlooked; without it, splitting evenly is impossible.
Visualizing remainder distribution clarifies why some parts have one node and others are empty.
Seeing links broken step-by-step reveals how the list is physically split, which is hard to grasp from code alone.
