Skip to content

Partition List

Given the head of a linked list and a value x, partition the list such that all nodes whose values are less than x come before nodes whose values are greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

InputxOutputExplanation
[1, 4, 3, 2, 5, 2]3[1, 2, 2, 4, 3, 5]All nodes < 3 move left; >= 3 stay right. Order preserved.
[2, 1]2[1, 2]Only 1 < 2, so it goes first; 2 stays.
[5, 3, 1, 4, 2]3[1, 2, 5, 3, 4][1, 2] < 3, then [5, 3, 4] >= 3.
  • The number of nodes in the list is in the range [0, 200].
  • -100 <= Node.val <= 100
  • -200 <= x <= 200
ApproachTimeSpaceMethodBest When
Two List HeadsO(n)O(1)Build two separate lists, mergeGeneral case — clean, easy to understand
Single List RearrangeO(n)O(1)Rearrange nodes in placeMemory ultra-constrained, prefers single list

* Both use O(1) extra space (two or more dummy/pointer nodes).

  • Pick Two List Heads if you want clarity and correctness. It is easier to reason about and less error-prone.
  • Pick Single List Rearrange if you want to practice advanced pointer manipulation or face extreme space constraints.
Clearest Logic
Two List Heads
O(n) time · O(1) space
Advanced Pointers
Single Rearrange
O(n) time · O(1) space
★ Recommended

Build two separate lists — one for nodes < x, one for nodes >= x — then connect them.

The key idea is simplicity: create two independent lists as you traverse, then splice them together. This avoids the complexity of tracking multiple pointers in one list.

⏱ Time O(n) Single pass through list 💾 Space O(1) Only pointer variables

Input: head = [1, 4, 3, 2, 5, 2], x = 3

Stepcurrent.val< 3?Actionsmaller listlarger list
11Append to smaller1
24Append to larger14
33Append to larger14 → 3
42Append to smaller1 → 24 → 3
55Append to larger1 → 24 → 3 → 5
62Append to smaller1 → 2 → 24 → 3 → 5
Merge: smaller.next = larger1 → 2 → 2 → 4 → 3 → 5

Animated walkthrough

How the two-head approach partitions a list

Watch two separate lists build, one for each partition, then merge at the end.

Step 1 of 8 Target: partition
Waiting to begin...
Array state
Memory / lookup state

function partitionTwoHeads(head, x):
smaller_dummy = new ListNode(0)
larger_dummy = new ListNode(0)
smaller_ptr = smaller_dummy
larger_ptr = larger_dummy
current = head
while current:
if current.val < x:
smaller_ptr.next = current
smaller_ptr = smaller_ptr.next
else:
larger_ptr.next = current
larger_ptr = larger_ptr.next
current = current.next
// Close the larger list
larger_ptr.next = null
// Connect the two lists
smaller_ptr.next = larger_dummy.next
return smaller_dummy.next
partition_list_two_heads.py
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def partition_list_two_heads(head: Optional[ListNode], x: int) -> Optional[ListNode]:
"""
Partition linked list into two groups: values < x and values >= x.
Uses two separate list heads and merges them at the end.
Time Complexity: O(n) where n is the number of nodes
Space Complexity: O(1) excluding the output list
"""
# Create dummy nodes for two lists
smaller_dummy = ListNode(0)
larger_dummy = ListNode(0)
# Pointers to build the two lists
smaller_ptr = smaller_dummy
larger_ptr = larger_dummy
# Partition nodes into two lists
current = head
while current:
if current.val < x:
smaller_ptr.next = current
smaller_ptr = smaller_ptr.next
else:
larger_ptr.next = current
larger_ptr = larger_ptr.next
current = current.next
# Close the larger list to avoid cycles
larger_ptr.next = None
# Connect the two lists
smaller_ptr.next = larger_dummy.next
return smaller_dummy.next
# Helper function to create a linked list from a list
def create_linked_list(values):
if not values:
return None
head = ListNode(values[0])
current = head
for val in values[1:]:
current.next = ListNode(val)
current = current.next
return head
# Helper function to convert linked list to list for easy testing
def linked_list_to_list(node):
result = []
while node:
result.append(node.val)
node = node.next
return result
# Test cases
head = create_linked_list([1, 4, 3, 2, 5, 2])
result = partition_list_two_heads(head, 3)
print(linked_list_to_list(result)) # [1, 2, 2, 4, 3, 5]
head = create_linked_list([2, 1])
result = partition_list_two_heads(head, 2)
print(linked_list_to_list(result)) # [1, 2]
head = create_linked_list([5, 3, 1, 4, 2])
result = partition_list_two_heads(head, 3)
print(linked_list_to_list(result)) # [1, 2, 5, 3, 4]
🎯 Interview Favourite

Rearrange nodes in a single pass by removing nodes with value < x from their current position and inserting them before the partition boundary.

This approach is more complex but demonstrates mastery of pointer manipulation. Instead of building separate lists, it rearranges the original list in place.

⏱ Time O(n) Single pass through list 💾 Space O(1) Only pointer variables

Input: head = [1, 4, 3, 2, 5, 2], x = 3

Phase 1: Find the partition point (first node >= x)

  • Start: 1 (< 3), 4 (>= 3) ← partition starts here

Phase 2: Rearrange nodes after partition

  • See 2 (< 3 but after partition), move before partition: 1 → 2 → 4 → 3 → 5 → 2
  • See 2 (< 3 but after partition), move before partition: 1 → 2 → 2 → 4 → 3 → 5
  • Final: 1 → 2 → 2 → 4 → 3 → 5
function partitionSingleRearrange(head, x):
dummy = new ListNode(0)
dummy.next = head
// Find partition point
prev = dummy
current = head
while current and current.val < x:
prev = current
current = current.next
// If all nodes < x or list empty, return
if not current:
return dummy.next
// Rearrange nodes < x found after partition
partition_prev = prev
run = current
while run:
if run.val < x:
// Remove from current position
current.next = run.next
// Insert before partition
run.next = partition_prev.next
partition_prev.next = run
partition_prev = run
run = current.next
else:
current = run
run = run.next
return dummy.next
partition_list_single_rearrange.py
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def partition_list_single_rearrange(head: Optional[ListNode], x: int) -> Optional[ListNode]:
"""
Partition linked list into two groups: values < x and values >= x.
Rearranges nodes in a single pass without creating separate lists.
Time Complexity: O(n) where n is the number of nodes
Space Complexity: O(1) excluding the output list
"""
# Create a dummy node to simplify edge cases
dummy = ListNode(0)
dummy.next = head
# Find the node just before the partition point
prev = dummy
current = head
while current and current.val < x:
prev = current
current = current.next
# Now prev is the last node with value < x (or dummy if all nodes >= x)
# current is the first node with value >= x (or None if all nodes < x)
# If all nodes are less than x or list is empty, return as is
if not current:
return dummy.next
# Now we need to insert nodes with value < x before the partition point
partition_prev = prev # Last node of < x group
run = current # Start from the partition point
while run:
if run.val < x:
# Remove run from its position
current.next = run.next
# Insert run before the partition point
run.next = partition_prev.next
partition_prev.next = run
# Move partition_prev forward
partition_prev = run
# Current stays the same to check the next node
run = current.next
else:
# Move forward
current = run
run = run.next
return dummy.next
# Helper function to create a linked list from a list
def create_linked_list(values):
if not values:
return None
head = ListNode(values[0])
current = head
for val in values[1:]:
current.next = ListNode(val)
current = current.next
return head
# Helper function to convert linked list to list for easy testing
def linked_list_to_list(node):
result = []
while node:
result.append(node.val)
node = node.next
return result
# Test cases
head = create_linked_list([1, 4, 3, 2, 5, 2])
result = partition_list_single_rearrange(head, 3)
print(linked_list_to_list(result)) # [1, 2, 2, 4, 3, 5]
head = create_linked_list([2, 1])
result = partition_list_single_rearrange(head, 2)
print(linked_list_to_list(result)) # [1, 2]
head = create_linked_list([5, 3, 1, 4, 2])
result = partition_list_single_rearrange(head, 3)
print(linked_list_to_list(result)) # [1, 2, 5, 3, 4]
CaseBehaviorExample
Empty listReturn null[][]
All nodes < xLarger list is null[1, 2] with x=5 → [1, 2]
All nodes >= xSmaller list is null[5, 6] with x=3 → [5, 6]
x is minimumAll nodes >= x[1, 2, 3] with x=-1 → [1, 2, 3]
x is maximumAll nodes < x[1, 2, 3] with x=100 → [1, 2, 3]
Single nodePartition trivially[5] with x=3 → [5]
Equal valuesPreserve order[3, 3, 3] with x=3 → [3, 3, 3] (all >= x)
Negative valuesTreat as regular integers[-1, 2, -3] with x=0 → [-1, -3, 2]
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
partition_list_optimized.py
"""
Solution for Partition List
"""
def solve():
"""Implementation for approach 3 of Partition List"""
pass
if __name__ == "__main__":
print("Solution ready")