Problem Overview
LeetCode 237 — Delete Node in a Linked List presents an unusual twist on the classic deletion problem. You are given access only to the node you want to delete — not the head of the list. Your task is to delete that node from the singly linked list. The node is guaranteed not to be the tail, so it always has a next node.
In a standard linked list deletion you find the previous node and set previous.next = target.next, effectively bypassing the target. That approach requires traversal from the head. Here, traversal is impossible because the head is not provided — you must solve the problem using only the reference to the target node itself.
The constraint that the node is not the tail is critical: it guarantees a next node always exists, which makes the trick described below possible in every valid input case.
- Given only the node to delete — head is NOT provided
- Delete the node from the singly linked list
- The node is guaranteed NOT to be the tail (it always has a next)
- All node values in the list are unique
- Cannot traverse from head — must work with only the target node reference
The Trick
Because you cannot access the previous node, the usual bypass (previous.next = node.next) is off the table. The insight is to flip the problem: instead of deleting the current node, delete the next node — but first copy the next node's value into the current node.
After the copy, the current node holds what the next node used to hold. Setting current.next = current.next.next then removes the next node from the chain. From any external perspective, the value that was originally in the target node has disappeared, and the list flows correctly.
This is a two-step operation: (1) node.val = node.next.val — overwrite current value with successor's value; (2) node.next = node.next.next — bypass the successor. Both steps run in O(1) time with no extra memory.
Trick Question: You're Not Deleting the Node Itself
This is a trick question: you are not actually deleting the node object you receive. You are overwriting it with its successor's data and then deleting the successor. The result is identical from the caller's perspective — the value is gone and the list is correct — but the node reference you were given still exists in memory, now holding different data. Interviewers love this distinction.
Two-Line Solution
The complete solution is two lines: node.val = node.next.val followed by node.next = node.next.next. That is the entire function body. No loops, no conditionals, no helper methods. This is one of the shortest valid solutions on LeetCode.
Time complexity is O(1): both operations are direct pointer or value assignments with no iteration. Space complexity is O(1): no auxiliary data structures are allocated.
In Python the method receives self and node as parameters and returns nothing. In Java the method is void and receives the node directly. Both implementations are two statements and return implicitly.
- 1Receive node — the node to delete (not the head)
- 2node.val = node.next.val → copy successor's value into current node
- 3node.next = node.next.next → bypass the successor, removing it from the list
- 4Done — the list no longer contains the original value; O(1) time, O(1) space
Why This Works
A linked list is defined entirely by its values and its next-pointers. Observers of the list only see (value, next) pairs; they have no knowledge of the physical node objects. By copying next's value into the current node and updating next to skip the old next, the sequence of (value, next) pairs seen by any traversal is exactly what it would be if the original node had been removed normally.
Concretely: before the operation the traversal sees ... → [A] → [B] → [C] → ... where A is the node to delete. After the operation the traversal sees ... → [B'] → [C] → ... where B' is the original A node now holding B's value and pointing to C. The node object for B no longer appears in any reachable path.
This works because the problem guarantees unique values and no external references to node.next that would expose the "deleted" successor object. In a production system with shared references, this trick could leave dangling pointers, but under LeetCode's constraints it is perfectly correct.
Subtle Issue: External References to node.next
This technique has a subtle issue: any external reference pointing directly to node.next now points to a "deleted" node — an object that has been bypassed and whose value was copied away. In practice this does not matter because the problem guarantees no such external references exist. In a real system where multiple threads or data structures might hold references to list nodes, this approach could cause confusion. Always mention this caveat in an interview.
Walk-Through Example
Consider the list 4 → 5 → 1 → 9 and the instruction to delete the node with value 5. You receive a reference to the node holding 5. You cannot reach the node holding 4 (the head is not given).
Step one: copy the next node's value (1) into the current node. The list now looks like 4 → 1 → 1 → 9 — there are temporarily two nodes with value 1, but this is an intermediate state visible only within the function.
Step two: bypass the successor by setting node.next = node.next.next. The second 1-node is removed from the chain. The final list is 4 → 1 → 9, which is exactly the expected result after deleting the node with value 5.
- 1Input list: 4 → 5 → 1 → 9, delete node with val = 5
- 2Receive reference to node [val=5, next→[val=1]]
- 3node.val = node.next.val → copy 1 into node: list becomes 4 → 1* → 1 → 9
- 4node.next = node.next.next → bypass second 1: list becomes 4 → 1* → 9
- 5Result: 4 → 1 → 9 (the value 5 is gone, list is correct)
Code Walkthrough — Python and Java
Python: def deleteNode(self, node): node.val = node.next.val; node.next = node.next.next. Two lines. No return value needed — the list is modified in place through the node reference. This is the shortest possible correct implementation.
Java: public void deleteNode(ListNode node) { node.val = node.next.val; node.next = node.next.next; }. Identical logic, two statements. The method is void; the mutation is visible to the caller through the shared object reference.
Both run in O(1) time and O(1) space. There is no iteration, no recursion, no extra data structure. This is likely the shortest solution for any LeetCode medium or easy problem you will encounter.
Does Not Work for the Tail Node
This approach fails completely for the tail node: node.next is null, so node.val = node.next.val throws a NullPointerException (Java) or AttributeError (Python). The problem explicitly guarantees the target is not the tail, but you must state this constraint clearly in an interview. If asked to handle tail deletion as well, you need the head reference so you can find the previous node and set previous.next = null.