Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Make a new node, point its next at the current head, and return the new node as the new head. Two lines, no traversal — O(1) time, O(1) space. The only thing you must not forget is returning the new head, because the head pointer changes.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you understand that prepending is O(1) (no traversal) and that the head pointer changes, so the function must return the new head.
Where candidates slip
Forgetting to return the new node (so the caller keeps the old head), or setting head = newNode locally without linking newNode.next to the old head.
How to stand out
State that it's O(1), that the head changes so you return the new node, and that this is exactly a stack push and the position-0 branch of insert-at-position.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachExplore the full treeCollapse the tree
How to read it:Prepending is constant time: link the new node to the old head and return it — no traversal.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 1 · Optimal
Prepend — Link New Node to Old Head (Optimal)
1Hint 1Explore hintHide hint
The new node must come before everything that exists now. What single pointer makes that true?
2Hint 2Explore hintHide hint
If the new node's next points at the current head, the new node is now first. What do you hand back to the caller?
3Hint 3Explore hintHide hint
Do you need to look at any other node, or even know the list's length, to prepend?
A · Core idea
We create the node and splice it in front of the list with a single link.
Why no traversal. Prepending touches only the front. The new node needs to point at whatever is currently first (the head), and nothing downstream changes — so there's nothing to walk. That's what makes it O(1), in contrast to appending (which is O(n) without a tail pointer).
Link before returning. Set newNode.next = head so the new node connects to the existing chain. If you skip this, the new node points at null and you've dropped the entire old list. The order is: build node, link its next to the old head, return the node.
Why we return the new head. The head pointer moves to the new node. A function that edits the list in place can't change the caller's head variable in languages that pass references by value, so the convention is to return the (possibly new) head and let the caller reassign. Head insertion always changes the head, making the return essential here.
Why empty lists need no branch. If head is null, newNode.next = null is exactly right — the new node becomes a one-element list. The same two lines cover empty and non-empty inputs.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
list = [2, 3], data = 1Array state
before
head on node 2
[1, 2, 3]C · Code with teaching comments
D · Why it works and complexityO(1) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Head insertion is the position-0 special case of insert-at-position, lifted out on its own: no predecessor to find, so no walk — just link and return. It's also precisely how a stack built on a linked list pushes.
ComplexityO(1) time, O(1) space — Two pointer assignments and a return, independent of list size → O(1) time. One new node, no extra structures → O(1) space.
E · Edge cases and pitfalls6list = [], data = 5 — newNode.next = null; return newNode → [5].Explore edge casesHide edge cases
Edge cases handled
list = [], data = 5newNode.next = null; return newNode → [5].list = [9], data = 7newNode.next = node 9; return newNode → [7, 9].
Pitfalls
- Not returning the new node — the caller keeps the old head and never sees the inserted element.
- Forgetting newNode.next = head — the new node points at null and the rest of the list is lost.
- Walking the list before inserting — needless O(n) work; prepending is O(1).
- Mutating the old head's pointers — unnecessary and can corrupt the list.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this.val = val; }Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Setting head locally without returning it
Reassigning a local parameter doesn't change the caller's variable in languages that pass references by value. The new node is built and linked but never reaches the caller, who still holds the old head.
Explore the code comparisonHide the code comparison
Setting head locally without returning it
Reassigning a local parameter doesn't change the caller's variable in languages that pass references by value. The new node is built and linked but never reaches the caller, who still holds the old head.
Don't write this
ListNode newNode = new ListNode(data);
newNode.next = head;
head = newNode; // local only — caller never sees thisWrite this instead
ListNode newNode = new ListNode(data);
newNode.next = head;
return newNode; // hand the new head back2Skipping the link to the old head
Returning the new node without pointing its next at the old head leaves newNode.next as null, so the rest of the list is detached and lost.
Explore the code comparisonHide the code comparison
Skipping the link to the old head
Returning the new node without pointing its next at the old head leaves newNode.next as null, so the rest of the list is detached and lost.
Don't write this
new_node = ListNode(data)
return new_node # new_node.next is None — old list droppedWrite this instead
new_node = ListNode(data)
new_node.next = head
return new_nodeRevise
Carry the pattern into the interview
Pattern to remember
Prepend: new node's next = old head, return new node
Code pattern to memorize
newNode = ListNode(data)
newNode.next = head
return newNodeRules to remember
- 1Set
newNode.next = headbefore returning — this links the new node to the rest of the list. - 2Return the new head. Prepending always changes the head, so the caller must receive
newNode. - 3No walk is needed — head insertion is O(1); never loop to the end.
- 4An empty list (
head == null) is not special:newNode.next = nullmakes the new node the sole element. - 5Don't mutate the old head's pointers — only the new node's
nextis set.
Use this pattern when
- Push onto the front of a singly linked list (stack-like LIFO behaviour)
- Build a list in reverse order of arrival in O(1) per insert
- Prepend without knowing or caring about the list length
- Implementing a stack or an adjacency list on top of linked nodes
Choose another pattern when
- You must insert at a specific middle index → walk to position − 1 first (insert at position)
- You must append to the back and order matters → keep a tail pointer for O(1), else it's O(n)
- You need a queue (FIFO) → head-insert alone gives a stack; pair with tail tracking for a queue
Interview takeaway
Head insertion is the cheapest list edit: point the new node at the old head and return it. It's O(1), it's how a linked-list stack pushes, and it's the position-0 case that every insert-at-position solution special-cases.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternConstant-time prepend: link the new node to the old head and return it. It's the position-0 case of insert-at-position and the push operation of a linked-list stack.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Insert at a Specific PositionGeneralize: position 0 is exactly head insert; otherwise walk to position − 1 and splice.
- Reverse Linked ListIterative reversal repeatedly prepends the current node to a growing reversed list — head insert in a loop.
- Add Two NumbersBuilds a result list node by node; the dummy-head pattern is the append counterpart to this prepend.