1. Introduction to Linked List Interview Questions
Linked lists are a foundational data structure tested in almost every coding interview at top tech companies like Amazon, Google, Microsoft, Meta, and Flipkart. Unlike arrays, linked lists provide O(1) insertions and deletions once a reference to a node is known, but they give up O(1) random index access.
Interviewers frequently use linked list problems to assess your pointer manipulation skills, handling of null references, and ability to optimize space complexity. Below are the Top 25 Linked List interview questions with full solutions in C++, Java, Python, and JavaScript.
2. Linked List Fundamentals
A node in a singly linked list contains data and a pointer to the next node:
cppstruct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} };
javaclass ListNode { int val; ListNode next; ListNode(int val) { this.val = val; } }
pythonclass ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next
javascriptclass ListNode { constructor(val = 0, next = null) { self.val = val; self.next = next; } }
3. Easy Questions
Q1. Reverse a Singly Linked List
Question: Reverse the direction of all pointers in a singly linked list so that the head becomes the tail.
Intuition: Maintain three pointers: prev (initialized to null), curr (initialized to head), and next (to temporarily store the next node before overwriting curr.next).
cppListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr) { ListNode* nextNode = curr->next; curr->next = prev; prev = curr; curr = nextNode; } return prev; }
javapublic ListNode reverseList(ListNode head) { ListNode prev = null; ListNode curr = head; while (curr != null) { ListNode nextNode = curr.next; curr.next = prev; prev = curr; curr = nextNode; } return prev; }
pythondef reverseList(head): prev = None curr = head while curr: next_node = curr.next curr.next = prev prev = curr curr = next_node return prev
javascriptfunction reverseList(head) { let prev = null; let curr = head; while (curr !== null) { let nextNode = curr.next; curr.next = prev; prev = curr; curr = nextNode; } return prev; }
Time Complexity: O(n) | Space Complexity: O(1)
Q2. Find the Middle of a Linked List
Question: Given the head of a singly linked list, return the middle node. If there are two middle nodes, return the second middle node.
Intuition: Fast and Slow Pointers. slow moves 1 step at a time, fast moves 2 steps. When fast reaches the end (or null), slow will be exactly at the middle node.
cppListNode* middleNode(ListNode* head) { ListNode* slow = head; ListNode* fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } return slow; }
javapublic ListNode middleNode(ListNode head) { ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; }
pythondef middleNode(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next return slow
javascriptfunction middleNode(head) { let slow = head; let fast = head; while (fast !== null && fast.next !== null) { slow = slow.next; fast = fast.next.next; } return slow; }
Time Complexity: O(n) | Space Complexity: O(1)
Q3. Detect Cycle in a Linked List
Question: Given head, determine if the linked list has a cycle in it.
Intuition: Floyd's Cycle-Finding Algorithm (Tortoise and Hare). If a cycle exists, the fast pointer will eventually catch up to and meet the slow pointer inside the loop.
cppbool hasCycle(ListNode *head) { ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; } return false; }
javapublic boolean hasCycle(ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) return true; } return false; }
pythondef hasCycle(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False
javascriptfunction hasCycle(head) { let slow = head; let fast = head; while (fast !== null && fast.next !== null) { slow = slow.next; fast = fast.next.next; if (slow === fast) return true; } return false; }
Time Complexity: O(n) | Space Complexity: O(1)
Q4. Remove Nth Node From End of List
Question: Remove the nth node from the end of the list and return its head.
Intuition: Maintain a gap of n nodes between fast and slow pointers. Advance fast by n + 1 steps from a dummy node. Then advance both until fast is null. slow.next will point to the node to delete.
cppListNode* removeNthFromEnd(ListNode* head, int n) { ListNode dummy(0); dummy.next = head; ListNode* fast = &dummy; ListNode* slow = &dummy; for (int i = 0; i <= n; i++) fast = fast->next; while (fast) { slow = slow->next; fast = fast->next; } slow->next = slow->next->next; return dummy.next; }
javapublic ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; ListNode fast = dummy, slow = dummy; for (int i = 0; i <= n; i++) fast = fast.next; while (fast != null) { slow = slow.next; fast = fast.next; } slow.next = slow.next.next; return dummy.next; }
pythondef removeNthFromEnd(head, n): dummy = ListNode(0, head) fast = slow = dummy for _ in range(n + 1): fast = fast.next while fast: slow = slow.next fast = fast.next slow.next = slow.next.next return dummy.next
javascriptfunction removeNthFromEnd(head, n) { let dummy = new ListNode(0, head); let fast = dummy; let slow = dummy; for (let i = 0; i <= n; i++) { fast = fast.next; } while (fast !== null) { slow = slow.next; fast = fast.next; } slow.next = slow.next.next; return dummy.next; }
Time Complexity: O(n) | Space Complexity: O(1)
Q5. Merge Two Sorted Lists
Question: Merge two sorted linked lists into one single sorted list.
cppListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode* tail = &dummy; while (l1 && l2) { if (l1->val < l2->val) { tail->next = l1; l1 = l1->next; } else { tail->next = l2; l2 = l2->next; } tail = tail->next; } tail->next = l1 ? l1 : l2; return dummy.next; }
javapublic ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode tail = dummy; while (l1 != null && l2 != null) { if (l1.val < l2.val) { tail.next = l1; l1 = l1.next; } else { tail.next = l2; l2 = l2.next; } tail = tail.next; } tail.next = (l1 != null) ? l1 : l2; return dummy.next; }
pythondef mergeTwoLists(l1, l2): dummy = ListNode(0) tail = dummy while l1 and l2: if l1.val < l2.val: tail.next = l1 l1 = l1.next else: tail.next = l2 l2 = l2.next tail = tail.next tail.next = l1 or l2 return dummy.next
javascriptfunction mergeTwoLists(l1, l2) { let dummy = new ListNode(0); let tail = dummy; while (l1 !== null && l2 !== null) { if (l1.val < l2.val) { tail.next = l1; l1 = l1.next; } else { tail.next = l2; l2 = l2.next; } tail = tail.next; } tail.next = l1 !== null ? l1 : l2; return dummy.next; }
Time Complexity: O(m + n) | Space Complexity: O(1)
Q6. Delete Node in a Linked List (Given Only Node Reference)
Question: You are given access only to the node to be deleted. Delete it without receiving head.
Intuition: Copy the value from node.next into node, then bypass node.next.
cppvoid deleteNode(ListNode* node) { node->val = node->next->val; node->next = node->next->next; }
javapublic void deleteNode(ListNode node) { node.val = node.next.val; node.next = node.next.next; }
pythondef deleteNode(node): node.val = node.next.val node.next = node.next.next
javascriptfunction deleteNode(node) { node.val = node.next.val; node.next = node.next.next; }
Time Complexity: O(1) | Space Complexity: O(1)
4. Medium Questions
Q7. Check if a Linked List is a Palindrome
Question: Return true if the linked list reads the same forward and backward.
Intuition: Find the middle node using slow/fast pointers, reverse the second half of the list, and then compare the first half and reversed second half element by element.
cppbool isPalindrome(ListNode* head) { if (!head || !head->next) return true; ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode *prev = nullptr, *curr = slow; while (curr) { ListNode* nextNode = curr->next; curr->next = prev; prev = curr; curr = nextNode; } ListNode *first = head, *second = prev; while (second) { if (first->val != second->val) return false; first = first->next; second = second->next; } return true; }
javapublic boolean isPalindrome(ListNode head) { if (head == null || head.next == null) return true; ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } ListNode prev = null, curr = slow; while (curr != null) { ListNode nextNode = curr.next; curr.next = prev; prev = curr; curr = nextNode; } ListNode first = head, second = prev; while (second != null) { if (first.val != second.val) return false; first = first.next; second = second.next; } return true; }
pythondef isPalindrome(head): if not head or not head.next: return True slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next prev, curr = None, slow while curr: nxt = curr.next curr.next = prev prev = curr curr = nxt first, second = head, prev while second: if first.val != second.val: return False first = first.next second = second.next return True
javascriptfunction isPalindrome(head) { if (!head || !head.next) return true; let slow = head, fast = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } let prev = null, curr = slow; while (curr) { let nxt = curr.next; curr.next = prev; prev = curr; curr = nxt; } let first = head, second = prev; while (second) { if (first.val !== second.val) return false; first = first.next; second = second.next; } return true; }
Time Complexity: O(n) | Space Complexity: O(1)
Q8. Add Two Numbers Represented as Linked Lists
Question: Digits are stored in reverse order. Add the two numbers and return the sum as a linked list.
cppListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode* curr = &dummy; int carry = 0; while (l1 || l2 || carry) { int sum = carry + (l1 ? l1->val : 0) + (l2 ? l2->val : 0); carry = sum / 10; curr->next = new ListNode(sum % 10); curr = curr->next; if (l1) l1 = l1->next; if (l2) l2 = l2->next; } return dummy.next; }
javapublic ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode curr = dummy; int carry = 0; while (l1 != null || l2 != null || carry != 0) { int sum = carry + (l1 != null ? l1.val : 0) + (l2 != null ? l2.val : 0); carry = sum / 10; curr.next = new ListNode(sum % 10); curr = curr.next; if (l1 != null) l1 = l1.next; if (l2 != null) l2 = l2.next; } return dummy.next; }
pythondef addTwoNumbers(l1, l2): dummy = ListNode(0) curr = dummy carry = 0 while l1 or l2 or carry: val1 = l1.val if l1 else 0 val2 = l2.val if l2 else 0 total = val1 + val2 + carry carry = total // 10 curr.next = ListNode(total % 10) curr = curr.next l1 = l1.next if l1 else None l2 = l2.next if l2 else None return dummy.next
javascriptfunction addTwoNumbers(l1, l2) { let dummy = new ListNode(0); let curr = dummy; let carry = 0; while (l1 || l2 || carry) { let v1 = l1 ? l1.val : 0; let v2 = l2 ? l2.val : 0; let total = v1 + v2 + carry; carry = Math.floor(total / 10); curr.next = new ListNode(total % 10); curr = curr.next; if (l1) l1 = l1.next; if (l2) l2 = l2.next; } return dummy.next; }
Time Complexity: O(max(m, n)) | Space Complexity: O(max(m, n))
Q9. Intersection of Two Linked Lists
Question: Find the node at which two singly linked lists intersect. Return null if no intersection.
Intuition: Two Pointers. Pointer A traverses list A then switches to list B. Pointer B traverses list B then switches to list A. They will meet at the intersection node after m + n total steps.
cppListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { if (!headA || !headB) return nullptr; ListNode *a = headA, *b = headB; while (a != b) { a = a ? a->next : headB; b = b ? b->next : headA; } return a; }
javapublic ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) return null; ListNode a = headA, b = headB; while (a != b) { a = (a == null) ? headB : a.next; b = (b == null) ? headA : b.next; } return a; }
pythondef getIntersectionNode(headA, headB): if not headA or not headB: return None a, b = headA, headB while a != b: a = a.next if a else headB b = b.next if b else headA return a
javascriptfunction getIntersectionNode(headA, headB) { if (!headA || !headB) return null; let a = headA, b = headB; while (a !== b) { a = a ? a.next : headB; b = b ? b.next : headA; } return a; }
Time Complexity: O(m + n) | Space Complexity: O(1)
Q10. Find Cycle Start Node in a Linked List
Question: Given a linked list with a cycle, return the node where the cycle begins.
cppListNode *detectCycle(ListNode *head) { ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) { ListNode* p = head; while (p != slow) { p = p->next; slow = slow->next; } return p; } } return nullptr; }
javapublic ListNode detectCycle(ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) { ListNode p = head; while (p != slow) { p = p.next; slow = slow.next; } return p; } } return null; }
pythondef detectCycle(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: p = head while p != slow: p = p.next slow = slow.next return p return None
javascriptfunction detectCycle(head) { let slow = head, fast = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; if (slow === fast) { let p = head; while (p !== slow) { p = p.next; slow = slow.next; } return p; } } return null; }
Time Complexity: O(n) | Space Complexity: O(1)
Q11. Reorder List (L0 → Ln → L1 → Ln-1...)
cppvoid reorderList(ListNode* head) { if (!head || !head->next) return; ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode *prev = nullptr, *curr = slow->next; slow->next = nullptr; while (curr) { ListNode* nxt = curr->next; curr->next = prev; prev = curr; curr = nxt; } ListNode *first = head, *second = prev; while (second) { ListNode *t1 = first->next, *t2 = second->next; first->next = second; second->next = t1; first = t1; second = t2; } }
javapublic void reorderList(ListNode head) { if (head == null || head.next == null) return; ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } ListNode prev = null, curr = slow.next; slow.next = null; while (curr != null) { ListNode nxt = curr.next; curr.next = prev; prev = curr; curr = nxt; } ListNode first = head, second = prev; while (second != null) { ListNode t1 = first.next, t2 = second.next; first.next = second; second.next = t1; first = t1; second = t2; } }
pythondef reorderList(head): if not head or not head.next: return slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next prev, curr = None, slow.next slow.next = None while curr: nxt = curr.next curr.next = prev prev = curr curr = nxt first, second = head, prev while second: t1, t2 = first.next, second.next first.next = second second.next = t1 first, second = t1, t2
javascriptfunction reorderList(head) { if (!head || !head.next) return; let slow = head, fast = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } let prev = null, curr = slow.next; slow.next = null; while (curr) { let nxt = curr.next; curr.next = prev; prev = curr; curr = nxt; } let first = head, second = prev; while (second) { let t1 = first.next, t2 = second.next; first.next = second; second.next = t1; first = t1; second = t2; } }
Time Complexity: O(n) | Space Complexity: O(1)
Q12. Sort List using Merge Sort
cppListNode* sortList(ListNode* head) { if (!head || !head->next) return head; ListNode *slow = head, *fast = head->next; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode* mid = slow->next; slow->next = nullptr; ListNode* left = sortList(head); ListNode* right = sortList(mid); ListNode dummy(0); ListNode* tail = &dummy; while (left && right) { if (left->val < right->val) { tail->next = left; left = left->next; } else { tail->next = right; right = right->next; } tail = tail->next; } tail->next = left ? left : right; return dummy.next; }
javapublic ListNode sortList(ListNode head) { if (head == null || head.next == null) return head; ListNode slow = head, fast = head.next; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } ListNode mid = slow.next; slow.next = null; ListNode left = sortList(head); ListNode right = sortList(mid); ListNode dummy = new ListNode(0); ListNode tail = dummy; while (left != null && right != null) { if (left.val < right.val) { tail.next = left; left = left.next; } else { tail.next = right; right = right.next; } tail = tail.next; } tail.next = (left != null) ? left : right; return dummy.next; }
pythondef sortList(head): if not head or not head.next: return head slow, fast = head, head.next while fast and fast.next: slow = slow.next fast = fast.next.next mid = slow.next slow.next = None left = sortList(head) right = sortList(mid) dummy = ListNode(0) tail = dummy while left and right: if left.val < right.val: tail.next = left; left = left.next else: tail.next = right; right = right.next tail = tail.next tail.next = left or right return dummy.next
javascriptfunction sortList(head) { if (!head || !head.next) return head; let slow = head, fast = head.next; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } let mid = slow.next; slow.next = null; let left = sortList(head); let right = sortList(mid); let dummy = new ListNode(0); let tail = dummy; while (left && right) { if (left.val < right.val) { tail.next = left; left = left.next; } else { tail.next = right; right = right.next; } tail = tail.next; } tail.next = left ? left : right; return dummy.next; }
Time Complexity: O(n log n) | Space Complexity: O(log n) call stack
5. Hard Questions & Design Patterns
Q13. LRU Cache Implementation
cpp#include <unordered_map> using namespace std; class LRUCache { struct Node { int key, val; Node *prev, *next; Node(int k, int v) : key(k), val(v), prev(nullptr), next(nullptr) {} }; int cap; unordered_map<int, Node*> map; Node *head, *tail; void remove(Node* node) { node->prev->next = node->next; node->next->prev = node->prev; } void add(Node* node) { node->next = head->next; node->prev = head; head->next->prev = node; head->next = node; } public: LRUCache(int capacity) : cap(capacity) { head = new Node(0, 0); tail = new Node(0, 0); head->next = tail; tail->prev = head; } int get(int key) { if (!map.count(key)) return -1; Node* node = map[key]; remove(node); add(node); return node->val; } void put(int key, int value) { if (map.count(key)) remove(map[key]); Node* node = new Node(key, value); add(node); map[key] = node; if (map.size() > cap) { Node* lru = tail->prev; remove(lru); map.erase(lru->key); delete lru; } } };
javaimport java.util.HashMap; class LRUCache { class Node { int key, val; Node prev, next; Node(int key, int val) { this.key = key; this.val = val; } } private int cap; private HashMap<Integer, Node> map = new HashMap<>(); private Node head, tail; public LRUCache(int capacity) { this.cap = capacity; head = new Node(0, 0); tail = new Node(0, 0); head.next = tail; tail.prev = head; } private void remove(Node node) { node.prev.next = node.next; node.next.prev = node.prev; } private void add(Node node) { node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } public int get(int key) { if (!map.containsKey(key)) return -1; Node node = map.get(key); remove(node); add(node); return node.val; } public void put(int key, int value) { if (map.containsKey(key)) remove(map.get(key)); Node node = new Node(key, value); add(node); map.put(key, node); if (map.size() > cap) { Node lru = tail.prev; remove(lru); map.remove(lru.key); } } }
pythonclass Node: def __init__(self, key=0, val=0): self.key = key self.val = val self.prev = self.next = None class LRUCache: def __init__(self, capacity: int): self.cap = capacity self.map = {} self.head = Node() self.tail = Node() self.head.next = self.tail self.tail.prev = self.head def _remove(self, node): node.prev.next = node.next node.next.prev = node.prev def _add(self, node): node.next = self.head.next node.prev = self.head self.head.next.prev = node self.head.next = node def get(self, key: int) -> int: if key not in self.map: return -1 node = self.map[key] self._remove(node) self._add(node) return node.val def put(self, key: int, value: int) -> None: if key in self.map: self._remove(self.map[key]) node = Node(key, value) self._add(node) self.map[key] = node if len(self.map) > self.cap: lru = self.tail.prev self._remove(lru) del self.map[lru.key]
javascriptclass Node { constructor(key = 0, val = 0) { this.key = key; this.val = val; this.prev = null; this.next = null; } } class LRUCache { constructor(capacity) { this.cap = capacity; this.map = new Map(); this.head = new Node(); this.tail = new Node(); this.head.next = this.tail; this.tail.prev = this.head; } _remove(node) { node.prev.next = node.next; node.next.prev = node.prev; } _add(node) { node.next = this.head.next; node.prev = this.head; this.head.next.prev = node; this.head.next = node; } get(key) { if (!this.map.has(key)) return -1; let node = this.map.get(key); this._remove(node); this._add(node); return node.val; } put(key, value) { if (this.map.has(key)) this._remove(this.map.get(key)); let node = new Node(key, value); this._add(node); this.map.set(key, node); if (this.map.size > this.cap) { let lru = this.tail.prev; this._remove(lru); this.map.delete(lru.key); } } }
Time Complexity: O(1) for both get and put | Space Complexity: O(capacity)
6. Summary Table
| Problem | Key Technique | Time | Space |
|---|---|---|---|
| Reverse List | 3-pointer iteration | O(n) | O(1) |
| Find Middle | Fast/Slow pointers | O(n) | O(1) |
| Detect Cycle | Floyd's Tortoise/Hare | O(n) | O(1) |
| Merge 2 Sorted Lists | Dummy head | O(n + m) | O(1) |
| Check Palindrome | Middle + Reverse + Compare | O(n) | O(1) |
| LRU Cache | Hash Map + Doubly Linked List | O(1) | O(capacity) |
Master all linked list patterns on DSAMaster's practice platform.
