Remove Linked List Elements: A Clean & Simple Visual Guide
5 min read
The Core Problem
Removing elements from a linked list sounds easy: find the node, take the arrow pointing to it, and reroute it to the node after it.
However, LeetCode 203 introduces a notorious edge case. What happens if the head node itself contains the target value? What if the first three nodes contain the target value? If we delete the head, where does our list begin?
Example 1:
- Input:
head = [1, 2, 6, 3, 4, 5, 6],val = 6 - Output:
[1, 2, 3, 4, 5]
Example 3 (The Edge Case):
- Input:
head = [7, 7, 7, 7],val = 7 - Output:
[](Empty List)
Trying to write if/else logic specifically for the head node results in messy, bug-prone code. We need a cleaner solution.
Interactive Visualization
The cleanest way to handle head deletions is using a Dummy Node (sometimes called a Sentinel Node). Use the interactive tool below to see exactly how attaching a temporary dummy node simplifies the entire process.
The Dummy Node Approach
Let's use a real-world train analogy.
Imagine you are a train dispatcher instructed to remove all broken boxcars (value 6) from a moving train. If the very first car is broken, uncoupling it is dangerous because you lose the locomotive!
The Dummy Node is a temporary locomotive you attach to the very front of the train before you start inspecting:
- You attach the Dummy Locomotive right in front of the actual head.
- You stand on the Dummy and look at the car right behind it (
curr.next). - If it's broken, you uncouple it and link your current car directly to the car after the broken one (
curr.next = curr.next.next). - If it's safe, you walk forward into that car (
curr = curr.next).
Because of the Dummy locomotive, the original "first" car is treated exactly like every other car in the middle of the train. When you finish, you simply detach your Dummy locomotive and return the rest of the train (return dummy.next).
Code Implementations
Here is the production-ready logic applying the Dummy Node technique. Notice how there are absolutely no special if statements checking for the head node.
TypeScript / JavaScript
class ListNode {
val: number;
next: ListNode | null;
constructor(val?: number, next?: ListNode | null) {
this.val = (val===undefined ? 0 : val);
this.next = (next===undefined ? null : next);
}
}
function removeElements(head: ListNode | null, val: number): ListNode | null {
// 1. Create the temporary dummy node pointing to the head
const dummy = new ListNode(-1, head);
let curr = dummy;
// 2. Iterate while there is a next node to check
while (curr.next !== null) {
if (curr.next.val === val) {
// Target found: bypass it
curr.next = curr.next.next;
} else {
// Target not found: step forward
curr = curr.next;
}
}
// 3. Return the real head (everything after the dummy)
return dummy.next;
}Python 3
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummy = ListNode(-1, head)
curr = dummy
while curr.next:
if curr.next.val == val:
# Bypass the node
curr.next = curr.next.next
else:
# Move to the next node
curr = curr.next
return dummy.nextJava
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; }
}
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(-1, head);
ListNode curr = dummy;
while (curr.next != null) {
if (curr.next.val == val) {
// Remove the node by rewiring the pointer
curr.next = curr.next.next;
} else {
// Advance the pointer
curr = curr.next;
}
}
return dummy.next;
}
}Complexity Analysis
- Time Complexity: O(N) — We traverse the entire linked list exactly once. The time it takes scales linearly with the number of nodes N in the list.
- Space Complexity: O(1) — We only allocate memory for a single dummy node and a
currpointer. The amount of extra memory used remains constant regardless of how massive the linked list becomes.
Summary & Key Takeaways
- Deleting nodes from the start of a linked list is the most common cause of
NullPointerExceptionbugs. - A Dummy Node (Sentinel Node) eliminates head edge cases by ensuring every node you need to check has a guaranteed "previous" node before it.
- When you bypass a node to delete it, do not move your
currpointer forward. The next node you just pulled into place might also need to be deleted!
Academic Callout: Mastering foundational data structure techniques like the dummy node ensures your code is robust and bug-free. Ensure your academic tracking is just as robust by utilizing the free AnaCGPA Calculator Tools to instantly convert and calculate your grades.
Topics
DSALinked ListLeetCode 203 SolutionTwo PointersDummy Node
Found this article helpful? Share it with others!