[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:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head, val):
if head == None:
return head
dummy = ListNode(0, head)
prev = dummy
curr = head
toDelete = None
while curr != None:
if curr.val == val:
prev.next = curr.next
toDelete = curr
else:
prev = curr
curr = curr.next
# Python does not need manual delete (kept for syntax consistency)
if toDelete != None:
toDelete = None
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
def removeElements(self, head, val):
# Handle empty list
if(head == None) return head
# Create dummy node to simplify edge cases
def dummy(self, 0, head)
ListNode prev = dummy # Previous valid node
ListNode curr = head # Current node being checked
ListNode toDelete = None
while curr != None:
if curr.val == val:
# Skip the current node
prev.next = curr.next
toDelete = curr # Mark for deletion
else :
# Move prev forward only when we keep the node
prev = curr
# Move to next node
curr = curr.next
# Delete removed node
if toDelete != None:
delete toDelete
toDelete = None
return dummy.next # Return new 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)