Delete the Last Node of a Linked List

Solve this Problem
Medium10–15 min
Topics
Companies
Practice:GFG ↗
Given the head of a singly linked list, delete the last node and return the head of the resulting list. If the list is empty or has just one node, the result is an empty list. Unlike deleting the first node, this one still requires a walk from head — a singly linked list keeps no pointer to its own tail, so the second-to-last node has to be found by checking one node ahead at each step (curr.next.next == null). Once found, dropping the last node is a single pointer write.

Test Case 1:

Input:head = [3, 8, 5, 1]
Output:[3, 8, 5]
Explanation:The last node (1) is removed.

Test Case 2:

Input:head = [9]
Output:[]
Explanation:Deleting the only node leaves an empty list — it was both the first and last node.

Test Case 3:

Input:head = []
Output:[]
Explanation:Nothing to delete — the empty list stays empty.

Constraints

  • 0 ≤ number of nodes in head ≤ 10⁴
  • -10⁹ ≤ node value ≤ 10⁹
  • Handle the empty list and the single-node list — both must return an empty list
🚀

Try the Dry Run

Don't just read the solution — watch it execute, one step at a time.

🧪Try your own test case
1class Solution {
2 public Node deleteAtEnd(Node head) {
3 if (head == null || head.next == null) {
4 return null;
5 }
6 Node curr = head;
7 while (curr.next.next != null) {
8 curr = curr.next;
9 }
10 curr.next = null;
11 return head;
12 }
13}
14
3
8
5
1
null
Variables
head3
COMPARE

head and head.next are both non-null, so skip the base cases and walk to find the second-to-last node.

Step 1 / 6

Approach & Solutions

Brute Force — Copy to Array Except the Last Node, Rebuild List

Brute

Walk the entire list into a plain array, then drop its last element. Throw the original list away and build a brand-new list from that array using a dummy + tail pointer. Correct, but it re-allocates n - 1 nodes just to drop one from the end.

TimeO(n)
SpaceO(n)
1// Node definition used in this problem: 2// class Node { 3// int val; 4// Node next; 5// } 6 7class Solution { 8 public Node deleteAtEnd(Node head) { 9 List<Integer> vals = new ArrayList<>(); 10 Node curr = head; 11 while (curr != null) { 12 vals.add(curr.val); 13 curr = curr.next; 14 } 15 if (!vals.isEmpty()) { 16 vals.remove(vals.size() - 1); 17 } 18 Node dummy = new Node(0); 19 Node tail = dummy; 20 for (int v : vals) { 21 tail.next = new Node(v); 22 tail = tail.next; 23 } 24 return dummy.next; 25 } 26}

Optimal — Traverse to the Second-to-Last Node, Snip the Tail

Optimal

A singly linked list has no pointer to its own tail, so the second-to-last node still has to be found by walking from head — but once found, deleting the last node is a single pointer write. Handle the empty list and the single-node list separately: both simply return null.

TimeO(n)
SpaceO(1) extra
1// Node definition used in this problem: 2// class Node { 3// int val; 4// Node next; 5// } 6 7class Solution { 8 public Node deleteAtEnd(Node head) { 9 if (head == null || head.next == null) { 10 return null; 11 } 12 Node curr = head; 13 while (curr.next.next != null) { 14 curr = curr.next; 15 } 16 curr.next = null; 17 return head; 18 } 19}

Related Problems