Delete the head node of a linked list

AS
Ackshaey Singh
Difficulty Easy
Time Complexity
O(1)
Space Complexity
O(1)
Linked list
Firecode Cisco

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

  1. Empty list (null head): Return null immediately
  2. Single node: After deletion, the list is empty, so return null (which is head.next)
  3. 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:

  1. If the list is empty (head is null), return null
  2. 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:

  1. Forgetting the null check: Accessing head.next when head is null causes a NullPointerException. Always guard against null input.

  2. Returning head instead of head.next: This returns the original list unchanged. The head is the node you want to remove, not keep.

  3. Trying to "free" memory in Java: Unlike C++, Java handles garbage collection automatically. There is no need to explicitly delete the old head node.

  4. 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:

  1. Clarify the edge cases first: "What should I return if the list is empty?" This shows you think before you code.

  2. 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.

  3. 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.

  4. 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.

  5. 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.next on 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;
    }
}

Frequently Asked Questions

What happens to the deleted head node after returning head.next?
In garbage-collected languages like Java, Python, and JavaScript, the old head node becomes unreachable once no references point to it, and the garbage collector reclaims its memory automatically. In languages like C++ where you manage memory manually, you must explicitly free the old head node with delete before returning the new head to avoid memory leaks.
Why is deleting the head node O(1) while deleting other nodes is O(n)?
Deleting the head requires no traversal because you already have a direct reference to it. You simply return head.next. Deleting a node at position k requires traversing k-1 nodes to find the preceding node and update its next pointer, making it O(k) in general and O(n) in the worst case for the last node.
What should the method return when the linked list is empty?
Return null (or None/nil depending on the language). An empty list has no head to delete, so you return null to indicate the list remains empty. Always handle this edge case first to avoid null pointer exceptions.
How does deleting the head of a linked list differ from deleting the head of an array?
Deleting the head of a linked list is O(1) because you just update the head pointer. Deleting the first element of an array is O(n) because every remaining element must shift one position to the left to fill the gap. This is one of the key advantages linked lists have over arrays for front-of-collection operations.
Can you delete the head node without returning a new head pointer?
Not cleanly. The caller holds a reference to the old head, and there is no way to update that reference from inside the method in most languages. The standard approach is to return the new head so the caller can reassign. Some implementations use a dummy/sentinel node before the real head to avoid this issue, but for this problem, returning head.next is the expected approach.
What is the difference between deleting a node and unlinking a node in a linked list?
Unlinking means removing a node from the chain by updating pointers so other nodes skip over it. Deleting goes further by also freeing the memory the node occupies. In garbage-collected languages, unlinking effectively causes deletion because the garbage collector reclaims unreachable objects. In C++, you must explicitly call delete after unlinking.
How does this problem relate to implementing a queue with a linked list?
A queue's dequeue operation removes the front element, which is exactly what deleting the head does. Linked-list-based queues use head deletion for O(1) dequeue and tail insertion for O(1) enqueue (with a tail pointer). This makes linked lists a natural fit for queue implementations where both operations must be constant time.
Is this problem ever asked in real coding interviews?
Yes, but usually as part of a larger problem or as a warm-up. Interviewers use it to gauge your comfort with pointer manipulation and null handling before moving to harder linked list problems like reversal, cycle detection, or merging sorted lists. Getting this right quickly builds confidence for the rest of the interview.