Delete the head node of a linked list
You're five minutes into a phone screen at Cisco when the interviewer asks, "Given a linked list, how would you remove the first element?" It sounds almost too easy, and that's precisely the trap. Candidates who rush through it often forget the null check or return the wrong node. This problem is a gateway to linked list fluency, and nailing it cleanly shows an interviewer you understand how pointers work under the hood.
TL;DR
To delete the head of a singly linked list, return head.next. The second node becomes the new head of the list. Handle the empty list edge case by returning null when head is null. This runs in O(1) time and O(1) space since no traversal or extra memory is needed.
Why This Problem Matters
Deleting the head of a linked list is the simplest linked list mutation you can perform, but it establishes a pattern you will use constantly: check for null, manipulate a pointer, return the updated reference. Every linked list problem from reversal to merge sort builds on this foundation. If you can handle head deletion without hesitating, you are ready for the harder stuff.
Linked Lists: A Quick Refresher
A singly linked list is a sequence of nodes where each node stores a value and a reference to the next node. The last node points to null, marking the end of the list.
Loading visualization...
The highlighted node is the head, the entry point to the entire list. Every operation on the list starts here. Unlike arrays, there is no index-based access. To reach node 4, you must walk through nodes 1, 2, and 3 first.
Understanding the Problem
Here is what we need to do:
Given: The head node of a singly linked list Task: Remove the head node and return the modified list Return: The new head of the list (the second node), or null if the list was empty
Let's visualize the transformation:
Before:
Loading visualization...
After deleting the head:
Loading visualization...
Node 1 is gone, and node 2 is the new head. The list is one node shorter.
Edge Cases to Consider
- Empty list (null head): Return null immediately
- Single node: After deletion, the list is empty, so return null (which is
head.next) - Two or more nodes: Return
head.next, which is the second node
Notice that cases 2 and 3 are actually the same operation. When there is only one node, head.next is null, which is exactly what we want to return. So really, the only special case is the empty list.
Solution Approach
Think about what deleting the head actually means. We are not erasing data from memory or shifting elements like we would in an array. We are simply telling the caller, "The list now starts at the second node."
In a linked list, the head is just a pointer. Changing what that pointer references is all it takes to "delete" the first node. The old head still exists in memory temporarily, but since nothing references it anymore, the garbage collector will clean it up (in Java, Python, JavaScript, and similar languages).
The algorithm is straightforward:
- If the list is empty (head is null), return null
- Otherwise, return
head.next
That is it. No loops, no temporary variables, no complex pointer rewiring.
Why head.next Works
When we return head.next, we are giving the caller a reference to the second node. From the caller's perspective, the list now starts at that second node. The old head is effectively removed from the chain.
Loading visualization...
The highlighted node (2) is head.next, which becomes the new head after deletion.
Implementation
Prefer a different language? Jump to solutions in other languages.
public class Solution {
public ListNode deleteHead(ListNode head) {
// If the list is empty, nothing to delete
if (head == null) {
return null;
}
// The second node becomes the new head
return head.next;
}
}
Let's trace through a few examples:
Example 1: [1, 2, 3]
- head is node 1, which is not null
- Return head.next, which is node 2
- Result:
[2, 3]
Example 2: [7]
- head is node 7, which is not null
- Return head.next, which is null
- Result: empty list (null)
Example 3: empty list (null)
- head is null
- Return null immediately
- Result: null
Visual Walkthrough
Here is the full before-and-after for a longer list:
Before (head highlighted):
Loading visualization...
After (new head highlighted):
Loading visualization...
Node 1 is gone. Node 2 is now the head of the list.
Complexity Analysis
Time Complexity: O(1)
We perform a single null check and return a pointer. No iteration, no recursion, no traversal. The operation takes constant time regardless of how many nodes the list contains.
This is one of the key advantages of linked lists over arrays. Removing the first element of an array requires shifting every other element one position to the left, which is O(n). With a linked list, it is O(1).
Space Complexity: O(1)
We use no extra data structures. We do not create any new nodes. We simply return an existing reference. The space usage is constant.
Common Pitfalls
Even with a problem this simple, I have seen candidates stumble in interviews:
-
Forgetting the null check: Accessing
head.nextwhen head is null causes a NullPointerException. Always guard against null input. -
Returning head instead of head.next: This returns the original list unchanged. The head is the node you want to remove, not keep.
-
Trying to "free" memory in Java: Unlike C++, Java handles garbage collection automatically. There is no need to explicitly delete the old head node.
-
Overcomplicating it: Some candidates create temporary variables, use loops, or try to modify the node's data. None of that is necessary. Just return
head.next.
Interview Tips
When this comes up in an interview:
-
Clarify the edge cases first: "What should I return if the list is empty?" This shows you think before you code.
-
State the complexity upfront: "This is an O(1) operation since we just return head.next." Interviewers appreciate when you identify the complexity before writing a single line of code.
-
Mention memory management if relevant: If the interviewer asks about C++, note that you would need to free the old head node to prevent memory leaks. This shows awareness of language-specific concerns.
-
Connect it to broader concepts: "This is essentially how a queue's dequeue operation works with a linked list." Showing you understand the bigger picture is more impressive than the solution itself.
-
Expect follow-ups: The interviewer will almost certainly ask a harder question next, like deleting a node at a specific position, deleting the tail, or reversing the list. Treat this as a warm-up and move through it efficiently.
Key Takeaways
- Deleting the head of a linked list is a single-line operation: return
head.next. The second node becomes the new head, and the old head is discarded. - Always handle the null/empty list case first. Accessing
head.nexton a null reference crashes your program. - This is O(1) time and O(1) space, which is faster than removing the first element of an array (O(n) due to shifting).
- In C++ and other non-garbage-collected languages, you must explicitly free the old head's memory after unlinking it.
- This pattern of "check for null, then manipulate the pointer" is the foundation for every linked list operation you will encounter in interviews.
Related Problems and Next Steps
Once you are comfortable with head deletion, these problems build on the same pointer manipulation skills:
- Insert a node at the front of a linked list (the inverse operation)
- Delete a node at a given position (requires traversal to find the predecessor)
- Reverse a linked list (the classic three-pointer technique)
- Find the middle of a linked list (fast and slow pointers)
Consistent practice is the key to succeeding in coding interviews. This problem and thousands of others are available on Firecode, where over 50,000 users have successfully prepared for technical interviews and landed six and seven-figure jobs at top tech companies. Whether you are just starting or preparing for your dream job, mastering fundamentals like this will set you up for success.
Solutions in Other Languages
Python
class Solution:
def delete_head(self, head):
if head is None:
return None
return head.next
JavaScript
class Solution {
deleteHead(head) {
if (head === null) {
return null;
}
return head.next;
}
}
TypeScript
class Solution {
deleteHead(head: ListNode | null): ListNode | null {
if (head === null) {
return null;
}
return head.next;
}
}
C++
In C++, you must manually free the old head to avoid memory leaks:
class Solution {
public:
ListNode* deleteHead(ListNode* head) {
if (head == nullptr) {
return nullptr;
}
auto next = head->next;
delete head;
return next;
}
};
Go
Go uses garbage collection, but the standard practice is to unlink the old head to help the GC:
func (s *Solution) DeleteHead(head *ListNode) *ListNode {
if head == nil {
return nil
}
next := head.Next
head.Next = nil
return next
}
Scala
class Solution {
def deleteHead(head: ListNode): ListNode = {
if (head == null) {
return null
}
return head.next
}
}
Kotlin
class Solution {
fun deleteHead(head: ListNode?): ListNode? {
if (head == null) {
return null
}
return head.next
}
}
Swift
class Solution {
func deleteHead(_ head: ListNode?) -> ListNode? {
if head == nil {
return nil
}
return head?.next
}
}
Ruby
class Solution
def delete_head(head)
return nil if head.nil?
head.next
end
end
Rust
pub fn delete_head(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
if head.is_none() {
return None;
}
head.unwrap().next
}
C#
public class Solution {
public ListNode? DeleteHead(ListNode? head) {
if (head == null) {
return null;
}
return head.next;
}
}
Dart
class Solution {
ListNode? deleteHead(ListNode? head) {
if (head == null) {
return null;
}
return head.next;
}
}
PHP
class Solution {
public function deleteHead(?ListNode $head): ?ListNode {
if ($head === null) {
return null;
}
return $head->next;
}
}