Skip to main content

Remove Linked List Elements - Mastering Pointer Manipulation

Β· 5 min read
Mahmut Salman
Software Developer

The Remove Linked List Elements problem is a fundamental linked list manipulation challenge that teaches essential pointer handling techniques. This problem is excellent for understanding when and why to use dummy nodes in linked list operations.

Problem Statement​

Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val == val, and return the new head.

Example 1:

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

Example 2:

Input: head = [], val = 1
Output: []

Example 3:

Input: head = [7,7,7,7], val = 7
Output: []

ListNode Definition​

public class ListNode {
int val;
ListNode next;

ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}

Solution Strategies​

Using a dummy node simplifies edge case handling and makes the code more uniform:

public class Solution {
public ListNode removeElements(ListNode head, int val) {
// Create dummy node to simplify edge cases
ListNode dummy = new ListNode(0);
dummy.next = head;

ListNode prev = dummy;
ListNode current = head;

while (current != null) {
if (current.val == val) {
// Skip the current node
prev.next = current.next;
} else {
// Move prev pointer forward
prev = current;
}
current = current.next;
}

return dummy.next;
}
}

Time Complexity: O(n) - traverse list once Space Complexity: O(1) - only use constant extra space

Approach 2: Without Dummy Node​

Handle the head removal case separately:

public class Solution {
public ListNode removeElements(ListNode head, int val) {
// Remove elements from the beginning
while (head != null && head.val == val) {
head = head.next;
}

// If list becomes empty
if (head == null) {
return null;
}

ListNode current = head;

// Remove elements from the middle and end
while (current.next != null) {
if (current.next.val == val) {
current.next = current.next.next;
} else {
current = current.next;
}
}

return head;
}
}

Time Complexity: O(n) Space Complexity: O(1)

Approach 3: Recursive Solution​

Leverage recursion to handle the removal elegantly:

public class Solution {
public ListNode removeElements(ListNode head, int val) {
// Base case
if (head == null) {
return null;
}

// Recursively process the rest of the list
head.next = removeElements(head.next, val);

// Return head if it should be kept, otherwise return head.next
return head.val == val ? head.next : head;
}
}

Time Complexity: O(n) Space Complexity: O(n) - recursion stack depth

Visual Walkthrough​

Let's trace through the dummy node approach with head = [1,2,6,3,4,5,6] and val = 6:

Initial:     dummy -> 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> null
prev current

Step 1: dummy -> 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> null
prev current (1 β‰  6, move prev)

Step 2: dummy -> 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> null
prev current (2 β‰  6, move prev)

Step 3: dummy -> 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> null
prev current (6 = 6, skip node)
After skip: dummy -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null
prev current

Step 4: dummy -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null
prev current (3 β‰  6, move prev)

...continue until end...

Final: dummy -> 1 -> 2 -> 3 -> 4 -> 5 -> null

Key Insights​

Why Use a Dummy Node?​

  1. Uniform Handling: No special case for removing the head node
  2. Simplified Logic: Always have a previous node to update
  3. Cleaner Code: Reduces conditional branches and potential bugs
  4. Edge Case Safety: Handles empty lists and single-element lists gracefully

Common Pitfalls​

  1. Memory Leaks: In languages with manual memory management, don't forget to free removed nodes
  2. Null Pointer Exceptions: Always check if nodes exist before accessing their properties
  3. Head Updates: When not using dummy nodes, remember to update the head reference
  4. Infinite Loops: Ensure you advance pointers correctly to avoid infinite loops

Comparison of Approaches​

ApproachProsConsBest Use Case
Dummy NodeUniform logic, fewer edge casesExtra node creationGeneral purpose, interviews
Without DummyNo extra spaceComplex head handlingMemory-constrained environments
RecursiveElegant, functional styleStack overflow risk, extra spaceEducational, functional programming
  1. Remove Duplicates from Sorted List: Similar pointer manipulation
  2. Merge Two Sorted Lists: Uses dummy node pattern
  3. Reverse Linked List: Fundamental pointer operations
  4. Delete Node in a Linked List: Different removal scenario

Advanced Considerations​

Performance Optimizations​

For very large lists with many removals:

public class Solution {
public ListNode removeElements(ListNode head, int val) {
// Early termination if all nodes need removal
if (head == null) return null;

ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
ListNode current = head;

while (current != null) {
if (current.val == val) {
// Batch remove consecutive elements
while (current != null && current.val == val) {
current = current.next;
}
prev.next = current;
} else {
prev = current;
current = current.next;
}
}

return dummy.next;
}
}

Conclusion​

The Remove Linked List Elements problem demonstrates essential linked list manipulation techniques. The dummy node approach is generally preferred for its simplicity and robustness against edge cases.

Key takeaways:

  • Dummy nodes simplify linked list manipulation
  • Pointer management is crucial for correct list operations
  • Edge cases (empty lists, single elements) must be carefully considered
  • Multiple approaches exist, each with different trade-offs

This problem serves as an excellent foundation for more complex linked list algorithms and is frequently used in technical interviews to assess pointer manipulation skills.