[Easy] 203. Remove Linked List Elements
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.
Examples
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: []
Constraints
- The number of nodes in the list is in the range
[0, 10^4]. 1 <= Node.val <= 500 <= val <= 50
Thinking Process
- Dummy Node: Using a dummy node simplifies edge cases, especially when the head needs to be removed
- Draw pointers before rewriting links.
- Dummy head simplifies insert/delete at the head.
- Slow/fast pointers find middle or detect cycles in one pass.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Iterative pointer walk (this problem) | O(n) | O(1) | Traversal, insertion |
| Dummy head node | O(n) | O(1) | Simplify head-edge cases |
| Reversal (3-pointer) | O(n) | O(1) | Reverse sublist or full list |
| Slow/fast pointers | O(n) | O(1) | Middle, cycle, merge lists |
Solution
Time Complexity: O(n) - We visit each node once
Space Complexity: O(1) - Only using constant extra space
The key insight is to use a dummy node to handle edge cases where the head itself needs to be removed. We traverse the list with two pointers: prev (previous node) and curr (current node), removing nodes that match the target value.
Solution: Iterative with Dummy Node
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode() { this.val = 0; this.next = null; }
* ListNode(int x) { this.val = x; this.next = null; }
* ListNode(int x, ListNode next) { this.val = x; this.next = next; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null) return head;
ListNode dummy = ListNode(0, head);
ListNode prev = &dummy;
ListNode curr = head;
ListNode toDelete = null;
while(curr != null) {
if (curr.val == val) {
prev.next = curr.next;
toDelete = curr;
} else {
prev = curr;
}
curr = curr.next;
if(toDelete != null) {
delete toDelete;
toDelete = null;
}
}
ListNode ret = dummy.next;
return ret;
}
}
Solution Explanation
Approach: Iterative pointer walk (this problem)
Key idea: 1. Dummy Node: Using a dummy node simplifies edge cases, especially when the head needs to be removed
How the code works:
- Dummy Node: Using a dummy node simplifies edge cases, especially when the head needs to be removed
- Draw pointers before rewriting links.
- Dummy head simplifies insert/delete at the head.
- Slow/fast pointers find middle or detect cycles in one pass.
Walkthrough — input head = [1,2,6,3,4,5,6], val = 6, expected output [1,2,3,4,5]:
- Initialize variables from the problem setup.
- Apply the main loop / recursion until the condition is met.
- Confirm the result matches the expected output.
| Approach | Time | Space | Pros | Cons | |———-|——|——-|——|——| | Iterative with Dummy | O(n) | O(1) | Space efficient, handles all cases | Requires memory management | | Recursive | O(n) | O(n) | Elegant, concise | Stack overflow risk for long lists | | Simplified Iterative | O(n) | O(1) | Simple, no memory management | Doesn’t free memory (fine for LeetCode) |
Algorithm Breakdown
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null) return head;
head.next = removeElements(head.next, val);
return head.val == val ? head.next : head;
}
}
Common Mistakes
- Empty list:
head = []→ return[] - Head needs removal:
head = [7,7,7,7], val = 7→ return[] - All nodes removed:
head = [1,1,1], val = 1→ return[] - No nodes removed:
head = [1,2,3], val = 4→ return[1,2,3] -
Remove from middle:
head = [1,2,3,2,4], val = 2→ return[1,3,4] - Not using dummy node: Makes it harder to handle head removal
- Incorrect pointer updates: Forgetting to update
prevonly when keeping a node - Memory leaks: Not deleting removed nodes
- Returning wrong pointer: Should return
dummy.next, nothead - Null pointer dereference: Not checking if
headisnullptrfirst
Complexity
| Approach | Time | Space | Pros | Cons | |———-|——|——-|——|——| | Iterative with Dummy | O(n) | O(1) | Space efficient, handles all cases | Requires memory management | | Recursive | O(n) | O(n) | Elegant, concise | Stack overflow risk for long lists | | Simplified Iterative | O(n) | O(1) | Simple, no memory management | Doesn’t free memory (fine for LeetCode) |
Related Problems
- 83. Remove Duplicates from Sorted List - Remove duplicates
- 82. Remove Duplicates from Sorted List II - Remove all duplicates
- 237. Delete Node in a Linked List - Delete without head reference
- 19. Remove Nth Node From End of List - Remove specific node
Optimization Notes
- Dummy Node Pattern: Essential for simplifying linked list deletion problems
- Memory Management: In production code, always delete removed nodes
- Early Termination: Could optimize by checking if list is empty first
- Pointer Safety: Always check for
nullptrbefore dereferencing
Key Takeaways
- Dummy Node: Using a dummy node simplifies edge cases, especially when the head needs to be removed
- Two Pointers:
prevtracks the previous valid node,currtraverses the list - Memory Management: Properly delete removed nodes to prevent memory leaks
- Pointer Updates: Only update
prevwhen we don’t remove a node; otherwise,prevstays the same
References
- LC 203: Remove Linked List Elements on LeetCode
- LeetCode Discuss — LC 203: Remove Linked List Elements
- LeetCode Editorial (may require premium)