Master this topic with zero to advance depth.
A Linked List is a linear data structure where elements are not stored in contiguous memory locations. Instead, each node contains a data field and a reference (pointer) to the next node.
| Type | Description | Pointers |
|---|---|---|
| Singly | Forward traversal only. | next |
| Doubly | Forward and backward traversal. | next, prev |
| Circular | Last node points back to head. | next (tail -> head) |
next pointers without using extra memory.| Feature | Linked List | Array |
|---|---|---|
| Access | (Sequential) | (Random) |
| Insert/Delete | (if at known node) | (Shift required) |
| Memory | Dynamic (Extra for pointers) | Static/Dynamic (Contiguous) |
Initial: [1] -> [2] -> [3] -> null
1. Point [1].next to null
2. Point [2].next to [1]
3. Point [3].next to [2]
Result: [3] -> [2] -> [1] -> nullLinked List Cycle
Given head, the head of a linked list, determine if the linked list has a cycle in it.
List: 3 -> 2 -> 0 -> -4 -> 2... (Cycle)
1. Slow=3, Fast=2
2. Slow=2, Fast=-4
3. Slow=0, Fast=0 (MEET!)
Result: trueExamples
There is a cycle where tail connects to the second node.
Intuition
The simplest way to detect a cycle is to keep track of all nodes seen. If we encounter a node that's already in our 'visited' set, it means there's a cycle.
List: 3 -> 2 -> 0 -> -4 (points back to 2)
Iter 1: node=3, Set={3}
Iter 2: node=2, Set={3, 2}
Iter 3: node=0, Set={3, 2, 0}
Iter 4: node=-4, Set={3, 2, 0, -4}
Iter 5: node=2, Found in Set! Cycle detected.Detailed Dry Run
Input: 3 -> 2 -> 0 -> -4 -> 2 (cycle)
{3}{3, 2}{3, 2, 0}{3, 2, 0, -4}2. 2 is in Seen. Cycle detected!⚠️ Common Pitfalls & Tips
O(N) space is often not allowed if O(1) is possible.
Intuition
If we can modify the list, we can point all seen nodes toward a sentinel 'Visited' node. If a node's next already points to this sentinel, we've closed the circle.
Nodes: [A] -> [B] -> [C] -> [B(cycle)]
1. At [A]: Save next [B], set [A].next = Sentinel. Move to [B].
2. At [B]: Save next [C], set [B].next = Sentinel. Move to [C].
3. At [C]: Save next [B], set [C].next = Sentinel. Move to [B].
4. At [B]: [B].next is already Sentinel! return true.Detailed Dry Run
1 -> 2 -> 1. Point 1.next to dummy. Point 2.next to dummy. 2.next is already dummy? No, 1.next was dummy. When we go from 2 to 1, 1.next is already dummy.
⚠️ Common Pitfalls & Tips
This destroys the original list.
Intuition
Use two pointers, slow and fast. slow moves one step, fast moves two. If there's a cycle, the fast pointer will eventually 'lap' the slow pointer.
List: 1 -> 2 -> 3 -> 4 -> 5 -> (back to 2)
Start: S=1, F=1
Step 1: S=2, F=3
Step 2: S=3, F=5
Step 3: S=4, F=3 (F wrapped around cycle)
Step 4: S=5, F=5 (MEET!)Detailed Dry Run
Input: 1 -> 2 -> 1...
slow=1, fast=2.slow = slow.next (2), fast = fast.next.next (2).⚠️ Common Pitfalls & Tips
Check both fast and fast.next for null to avoid errors.
Remove Nth Node From End of List
Given the head of a linked list, remove the n^{th} node from the end of the list and return its head.
List: 1 -> 2 -> 3 -> 4 -> 5, n = 2
Step 1: Move Fast pointer n=2 steps ahead.
Dummy -> 1 -> 2 -> 3 -> 4 -> 5
S F
Step 2: Move both S and F until F reaches the end.
Dummy -> 1 -> 2 -> 3 -> 4 -> 5 -> null
S F
Step 3: S.next = S.next.next (Removes 4)
1 -> 2 -> 3 -> 5Examples
The second node from the end is 4. Removing it results in [1,2,3,5].
Intuition
To remove the n^{th} node from the end, we calculate the total length L of the list. The node to remove is at index (L - n) from the start (0-indexed if using a dummy node).
Detailed Dry Run
Input: 1->2->3->4->5, n=2. Length = 5.
Target to skip: 5 - 2 = 3 steps from dummy.
| Steps | Curr | Action |
|---|---|---|
| 0 | Dummy | Move |
| 1 | 1 | Move |
| 2 | 2 | Move |
| 3 | 3 | Stop. curr is now at node 3. curr.next (node 4) is the one to remove. |
curr.next = curr.next.next (node 3 points to node 5) |
⚠️ Common Pitfalls & Tips
You must handle the case where the head itself is removed. Using a dummy node simplifies this.
Intuition
We can solve this problem recursively by traversing to the end of the list and then backtracking. During backtracking, we keep track of the node count from the end. When it reaches n, we remove the next node.
head.next.n, the current node's next should be skipped.Detailed Dry Run
Input: 1->2->3, n=1
1, 2, 3 to stack.3, count=1. count == n, so return to 2 acknowledging 3 should be removed? (Actually implementation differs slightly).⚠️ Common Pitfalls & Tips
O(L) space due to recursion might be an issue for very long lists.
Intuition
Use two pointers, fast and slow. Move fast n steps ahead. Then move both until fast reaches the end. slow will now be just before the node to be removed.
fast and slow pointers at a dummy node.fast pointer n+1 steps forward.fast pointer reaches the end (null).slow.next is the node to be removed. Update slow.next = slow.next.next.Detailed Dry Run
Input: 1->2->3->4->5, n=2
fast, slow at dummy.fast 3 steps: fast points at 3.fast at 4, slow at 1; fast at 5, slow at 2; fast at null, slow at 3.slow.next (node 4) is removed.⚠️ Common Pitfalls & Tips
The gap between fast and slow must be exactly n+1 to land 'slow' on the node before the target.
List: 1 -> 2 -> 3 -> 4 -> 5, n = 2
[D] -> [1] -> [2] -> [3] -> [4] -> [5] -> null
S,F
1. Move Fast 3 steps (n+1):
[D] -> [1] -> [2] -> [3] -> [4] -> [5]
S F
2. Move both until F is null:
[D] -> [1] -> [2] -> [3] -> [4] -> [5] -> null
S F
3. S.next = S.next.next (skip 4):
[3] -> [5]Partition List
Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions.
List: 1 -> 4 -> 3 -> 2 -> 5 -> 2, x = 3
Step 1: Create two lists: Small and Large.
Step 2: Traverse and assign:
Small: 1 -> 2 -> 2
Large: 4 -> 3 -> 5
Step 3: Connect Small.next to Large.next.
Result: 1 -> 2 -> 2 -> 4 -> 3 -> 5Examples
Nodes less than 3 are 1, 2, 2. Nodes >= 3 are 4, 3, 5. Order is preserved.
Intuition
Iterate through the list twice (or once with two collections). In the first pass, collect all nodes smaller than x. In the second pass, collect all nodes greater than or equal to x. Finally, rebuild the list.
List: 1 -> 4 -> 3 -> 2, x=3
Pass 1 (<3): [1, 2]
Pass 2 (>=3): [4, 3]
Combined: [1, 2, 4, 3]
New List: 1 -> 2 -> 4 -> 3Iterate and store values in two separate lists (or an array). Traverse the stored values to create a new linked list.
Detailed Dry Run
Input: [1, 4, 3, 2], x=3
Lists: Small=[1, 2], Large=[4, 3].
Rebuild: 1->2->4->3.
⚠️ Common Pitfalls & Tips
O(N) space is not ideal. Rebuilding the list creates new node objects.
Intuition
If we don't care about relative order, we could swap values. Since we must preserve it, this approach involves detaching nodes >= x and appending them to a secondary 'large' list, while keeping < x nodes in the 'small' list.
List: 1 -> 4 -> 3 -> 2, x=3
Small Head: [DummyS]
Large Head: [DummyL]
Node 1: <3, DummyS -> 1
Node 4: >=3, DummyL -> 4
Node 3: >=3, DummyL -> 4 -> 3
Node 2: <3, DummyS -> 1 -> 2
Connect: DummyS -> 1 -> 2 -> 4 -> 3Iterate through the list. If a node is >= x, move it to a temporary 'large' list. If < x, keep it in the 'small' list. This is similar to Level III but implemented strictly with node movement.
Detailed Dry Run
Identical to Level III intuition but focused on pointer manipulation without separate head nodes.
⚠️ Common Pitfalls & Tips
Strict pointer management is required to avoid cycles or losing nodes.
Intuition
The simplest way to maintain relative order is to create two separate lists: one for nodes smaller than x and another for nodes greater than or equal to x. Finally, link the end of the first list to the head of the second list.
Detailed Dry Run
Input: 1->4->3->2, x=3
144->31->21->2 to 4->3 -> 1->2->4->3⚠️ Common Pitfalls & Tips
Remember to set after.next = null to avoid cycles in the list.
Merge K Sorted Lists
You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
lists = [
1->4->5,
1->3->4,
2->6
]
Min-Heap State:
1. Insert heads: [1, 1, 2]
2. Extract 1, add next(4): Heap = [1, 2, 4]
3. Extract 1, add next(3): Heap = [2, 3, 4]
4. Extract 2, add next(6): Heap = [3, 4, 6]...
Merged Result:
1->1->2->3->4->4->5->6Examples
Intuition
The simplest approach is to ignore the linked list structure initially. We can traverse all the linked lists, collect all the values into an array, sort the array, and then build a new linked list from the sorted array.
Detailed Dry Run
lists = [[1,4,5],[1,3,4],[2,6]]
⚠️ Common Pitfalls & Tips
O(N log N) time and O(N) space. Not optimal for large lists.
Lists: [1->4, 1->3]
1. Array: [1, 4, 1, 3]
2. Sorted: [1, 1, 3, 4]
3. Linked: 1 -> 1 -> 3 -> 4Intuition
Merge lists in pairs, decreasing the number of lists by half in each step. This is more efficient than merging one by one and avoids the overhead of a Min-Heap if k is small.
[L1, L2, L3, L4]
\ / \ /
[L12] [L34]
\ /
[Final]Detailed Dry Run
Lists = [L1, L2, L3, L4]. 1. Merge(L1, L2)=L12, Merge(L3, L4)=L34. 2. Merge(L12, L34) = Result.
⚠️ Common Pitfalls & Tips
Deep recursion could cause stack overflow in some environments, though log(k) is usually safe.
Intuition
Use a Min-Heap (Priority Queue) to always extract the smallest current node among the heads of all k lists.
Detailed Dry Run
lists = [[1,4,5], [1,3,4], [2,6]]
⚠️ Common Pitfalls & Tips
In Python, using a tie-breaker like i or a wrapper is necessary for heapq when values are equal.
Reverse Nodes in k-Group
Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is.
List: 1 -> 2 -> 3 -> 4 -> 5, k = 3
1. Group [1,2,3] -> Reverse -> 3 -> 2 -> 1
2. Group [4,5] (Size 2 < 3) -> Keep 4 -> 5
Result: 3 -> 2 -> 1 -> 4 -> 5Examples
The list is reversed in groups of size 2.
Intuition
We can solve the problem recursively by reversing the first k nodes and then calling the function recursively for the rest of the list.
Detailed Dry Run
List: 1->2->3->4->5, k=2.
⚠️ Common Pitfalls & Tips
O(N/k) recursion stack space is used. The last group with < k nodes must be left as is.
Intuition
Traverse the list and push k nodes onto a stack. If we have k nodes, pop them to reverse. If we reach the end with fewer than k nodes, append them as is.
List: 1 -> 2 -> 3 -> 4, k=2
Iter 1: Stack=[1, 2]. Pop: 2 -> 1
Iter 2: Stack=[3, 4]. Pop: 4 -> 3
Result: 2 -> 1 -> 4 -> 3Detailed Dry Run
List: 1->2->3, k=2. Stack=[1, 2], pop to get 2->1. Append 3.
Intuition
To achieve O(1) space, we can iterate through the list and reverse the nodes in-place group by group. We use a dummy node to handle the head of the list properly.
Detailed Dry Run
Dummy -> 1 -> 2 -> 3 -> 4 -> 5, k=2.
⚠️ Common Pitfalls & Tips
Careful with pointer manipulations. Ensure the count check correctly stops when fewer than k nodes remain.
Merge Two Sorted Lists
Merge two sorted linked lists and return it as a new sorted list. The new list should be made by splicing together the nodes of the first two lists.
L1: 1 -> 2 -> 4
L2: 1 -> 3 -> 4
Result: 1 -> 1 -> 2 -> 3 -> 4 -> 4Examples
Intuition
Use a dummy node and a tail pointer. Compare the heads of both lists, attach the smaller node to the tail, and move pointers forward.
L1: [1] -> [3]
L2: [2] -> [4]
1. Compare 1 and 2. Attach 1. Tail=[1], L1=[3]
2. Compare 3 and 2. Attach 2. Tail=[2], L2=[4]
3. Compare 3 and 4. Attach 3. Tail=[3], L1=null
4. Attach remaining L2: Tail points to [4].Detailed Dry Run
L1: 1->2, L2: 1->3. Dummy -> 1 (L1) -> 1 (L2) -> 2 (L1) -> 3 (L2).
⚠️ Common Pitfalls & Tips
Don't forget to attach the remaining nodes at the end.
Intuition
Merge the lists in-place by always picking the smaller node as the current head and moving pointers. This avoids the use of a dummy node by handling the first node comparison separately.
Detailed Dry Run
L1: 1->3, L2: 2->4.
⚠️ Common Pitfalls & Tips
Must handle the head assignment carefully to avoid null pointer exceptions.
Reverse Linked List
Given the head of a singly linked list, reverse the list, and return the reversed list.
List: 1 -> 2 -> 3 -> null
Step 1: Current=1, Next=2. 1.next points to null.
Step 2: Current=2, Next=3. 2.next points to 1.
Step 3: Current=3, Next=null. 3.next points to 2.
Result: 3 -> 2 -> 1 -> nullExamples
Intuition
Push all node values onto a stack. Since a stack is Last-In-First-Out (LIFO), popping them will give the values in reverse order. Then, create a new list with these values.
Detailed Dry Run
List: 1->2->3.
⚠️ Common Pitfalls & Tips
O(N) space makes this less efficient than in-place methods.
Intuition
Base case: if head is null or next node is null, return head. Recursive step: reverse the rest of the list, then point the next node's next back to head.
Detailed Dry Run
1->2->3.
⚠️ Common Pitfalls & Tips
Easy to forget to set head.next = null, causing deep cycles.
Intuition
Use three pointers: prev, curr, and next. Iterate through the list, changing each node's next pointer to point to the prev node.
Detailed Dry Run
1->2->3. Prev=null, Curr=1.
⚠️ Common Pitfalls & Tips
Make sure to return prev at the end, as curr will be null.
[1] -> [2] -> [3] -> null
p=null, c=1
Iter 1: [1].next=null, p=1, c=2
Iter 2: [2].next=1, p=2, c=3
Iter 3: [3].next=2, p=3, c=null
Return p=3: [3] -> [2] -> [1] -> nullMiddle of the Linked List
Given the head of a singly linked list, return the middle node of the linked list. If there are two middle nodes, return the second middle node.
List: 1 -> 2 -> 3 -> 4 -> 5
Slow moves 1 step, Fast moves 2 steps.
Start: Slow=1, Fast=1
Step 1: Slow=2, Fast=3
Step 2: Slow=3, Fast=5
Result: 3 is middle node.Examples
Intuition
Convert the linked list into an array. Then, return the node at index size / 2.
Detailed Dry Run
List: 1->2->3. Array: [1, 2, 3]. Middle index 3/2 = 1. Array[1] = 2.
⚠️ Common Pitfalls & Tips
O(N) space is not optimal.
List: A -> B -> C -> D
Array: [A, B, C, D]
Size: 4
Middle: size/2 = 2
Result: Array[2] = CIntuition
First, traverse the list to find the total number of nodes (N). Then, traverse a second time for N/2 steps to reach the middle node.
Detailed Dry Run
List: 1->2->3->4.
⚠️ Common Pitfalls & Tips
Ensure the loop runs exactly length/2 times to handle both even and odd lengths correctly.
Intuition
Use two pointers, slow and fast. Move slow one step at a time and fast two steps at a time. When fast reaches the end, slow will be at the middle.
Detailed Dry Run
1->2->3->4->5.
⚠️ Common Pitfalls & Tips
For even length lists, ensure the second middle node is returned (this implementation does that).
Reorder List
You are given the head of a singly linked-list. The list can be represented as:
L0 → L1 → … → Ln - 1 → Ln
Reorder the list to be on the following form:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
You may not modify the values in the list's nodes. Only nodes themselves may be changed.
List: 1 -> 2 -> 3 -> 4
1. Find middle: 2
2. Reverse second half: 4 -> 3
3. Merge lists: 1 -> 4 -> 2 -> 3Examples
Intuition
Store all nodes in an array. Use two pointers (start and end) to reorder the nodes by changing their next pointers.
Detailed Dry Run
1->2->3->4. Array: [1, 2, 3, 4].
⚠️ Common Pitfalls & Tips
O(N) space makes this less efficient than in-place methods.
List: 1 -> 2 -> 3 -> 4
Array: [1, 2, 3, 4]
i=0, j=3: 1.next=4, 4.next=2
i=1, j=2: 2.next=3
i=2, j=2: Break. 3.next=null
Result: 1 -> 4 -> 2 -> 3Intuition
Store all nodes in a stack. Since a stack is LIFO, popping from it gives nodes from the end. Only pop N/2 nodes and interleave them with the first half of the list.
Detailed Dry Run
1->2->3->4. Stack: [1, 2, 3, 4].
⚠️ Common Pitfalls & Tips
Be careful to set the final next pointer to null to prevent cycles.
Intuition
Find the middle of the list. Reverse the second half. Merge the two halves one by one.
Detailed Dry Run
1->2->3->4.
⚠️ Common Pitfalls & Tips
Ensure to cut the list at the middle (slow.next = null) to avoid cycles.
Copy List with Random Pointer
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
Original: [7,null] -> [13,0] -> [11,4] -> [10,2] -> [1,0]
Where [val, random_index]
Approach: Interweaving
1. Interweave: 7 -> 7' -> 13 -> 13' -> ...
2. Assign random: 7'.random = 7.random.next
3. Separate: 7 -> 13 and 7' -> 13'Examples
Intuition
Use a hash map to store the mapping between the original node and the new node. First pass: create all clone nodes and map them. Second pass: link next and random pointers using the map.
Detailed Dry Run
Map: {7: 7', 13: 13', ...}.
⚠️ Common Pitfalls & Tips
O(N) space is required for the map. Ensure the Node structure (with val, next, random) is understood.
Original: [A] -> [B] -> [C]
Map: {A: A', B: B', C: C'}
Step 2: A'.next = Map[B], A'.random = Map[C]Intuition
Use recursion to traverse the list. For each node, create a clone if it doesn't exist, and store it in a map. Then recursively copy next and random pointers. This naturally handles cycles and arbitrary pointers.
Detailed Dry Run
copy(7) -> 7'.
⚠️ Common Pitfalls & Tips
Recursive depth can be an issue for very large lists. Ensure the map is used to prevent infinite recursion on random pointers.
Intuition
Instead of a hash map, we can interweave the cloned nodes with the original nodes. Step 1: Create a clone and insert it after each original node. Step 2: Assign random pointers. Step 3: Separate the interweaved lists.
Detailed Dry Run
7 -> 13 to 7 -> 7' -> 13 -> 13'.
⚠️ Common Pitfalls & Tips
Be extremely careful when separating the interweaved list; you must restore the original list as well.
Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
(2 -> 4 -> 3) + (5 -> 6 -> 4) = 7 -> 0 -> 8
Explanation: 342 + 465 = 807.Examples
Intuition
Iterate through both lists, adding digits along with a carry. Create a new node for each digit of the sum.
Detailed Dry Run
l1=[2,4], l2=[5,6].
⚠️ Common Pitfalls & Tips
Be careful with the final carry; don't forget to add a node for it if it's non-zero.
Intuition
Treat the addition of two lists as a recursive operation: add the current nodes and carry, then recurse for the next nodes.
Detailed Dry Run
l1=[2,4], l2=[5,6].
⚠️ Common Pitfalls & Tips
Ensure the base case handles the final carry correctly.
Intuition
To optimize space, we can re-use the nodes of the longer list instead of creating new ones. However, this is only possible if modifying the input is allowed.
Detailed Dry Run
l1=[2,4], l2=[5,6,7]. Re-use l2.
⚠️ Common Pitfalls & Tips
Modifying input lists is generally discouraged unless specified, but it's a valid 'memory-constrained' strategy.
Intersection of Two Linked Lists
Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null.
List A: a1 -> a2
\
c1 -> c2 -> c3
/
List B: b1 -> b2 -> b3
Intersection at c1.Examples
Intuition
Traverse the first list and store all node addresses in a hash set. Then, traverse the second list and check if any node exists in the set.
Detailed Dry Run
List A: [A, B, C]. Set: {A, B, C}. List B: [D, E, B, C]. Search D (no), E (no), B (yes!). Intersection at B.
⚠️ Common Pitfalls & Tips
O(N) space is not ideal. Note that you must store node pointers/references, not just values.
Intuition
Calculate lengths of both lists. Move the pointer of the longer list forward by the difference. Then move both pointers together until they meet.
A: 1 -> 2 -> 3 -> C1 (Len 4)
B: 4 -> C1 (Len 2)
Diff = 2. Advance pointer A by 2 steps.
Pointer A starts at 3, B starts at 4.
Move both: A=C1, B=C1. Match!Detailed Dry Run
A: [4,1,8,4,5], B: [5,6,1,8,4,5]. LenA=5, LenB=6. Diff=1. Move B forward by 1 (to 6). Both move together: (1,1), (8,8) -> Intersect at 8.
Intuition
Use two pointers, pA and pB. Traverse both lists. When a pointer reaches the end, redirect it to the head of the other list. They will meet at the intersection point or both become null.
Detailed Dry Run
A: [1,2,c], B: [3,c].
⚠️ Common Pitfalls & Tips
The pointers will meet even if there is no intersection (both will be null).
Palindrome Linked List
Given the head of a singly linked list, return true if it is a palindrome or false otherwise.
List: 1 -> 2 -> 2 -> 1
1. Find mid: 2 (first 2)
2. Reverse second half: 1 -> 2
3. Compare halves: (1,2) == (1,2) -> trueExamples
Intuition
Copy the values of the linked list into an array and then check if the array is a palindrome using two pointers.
Detailed Dry Run
1->2->2->1. Array: [1,2,2,1]. i=0, j=3: 1==1. i=1, j=2: 2==2. Match!
⚠️ Common Pitfalls & Tips
O(N) space is required.
List: 1 -> 2 -> 3 -> 2 -> 1
Array: [1, 2, 3, 2, 1]
i=0, j=4: 1==1
i=1, j=3: 2==2
Match!Intuition
Compare nodes from outside-in. A stack helps us access nodes in reverse order.
Stack: [1, 2, 2, 1]
Compare Pop(1) with Head(1) -> MatchIntuition
Find the middle of the linked list using fast/slow pointers. Reverse the second half of the list. Compare the two halves. Finally, restore the list (optional).
Detailed Dry Run
1->2->2->1.
⚠️ Common Pitfalls & Tips
Be careful when the list length is odd; the slow pointer will be exactly at the middle node, and reversing from it works fine.
Remove Duplicates from Sorted List
Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well.
List: 1 -> 1 -> 2 -> 3 -> 3
1. 1 == 1. 1.next points to 2.
2. 2 != 1. Move to 2.
3. 3 == 3. 3.next points to null.
Result: 1 -> 2 -> 3Examples
Intuition
Since the list is sorted, nodes with the same value will be adjacent. Traverse the list, and if a node's value equals its next node's value, skip the next node.
Detailed Dry Run
1->1->2.
⚠️ Common Pitfalls & Tips
Only works on sorted lists. For unsorted lists, a hash set would be needed.
Intuition
The recursive approach checks the head and its next node. If they have the same value, it skips the current head and returns the result of the recursive call on the next node.
Detailed Dry Run
1->1->2.
⚠️ Common Pitfalls & Tips
Recursion depth is proportional to the number of nodes.
Intuition
Using a dummy node isn't strictly necessary for this problem (since the head never changes), but it's a good practice to ensure consistency across all linked list problems.
dummy node pointing to head.curr pointer.curr with curr.next and skip duplicates.Detailed Dry Run
Dummy -> 1 -> 1 -> 2.
⚠️ Common Pitfalls & Tips
Ensure the dummy value doesn't conflict with valid node values.
Linked List Cycle II
Given the head of a linked list, return the node where the cycle begins. If there is no cycle, return null.
3 -> 2 -> 0 -> -4
^ |
+----------+
Cycle starts at node with value 2.Examples
Intuition
Store visited nodes in a set. The first node we encounter that is already in the set is the start of the cycle.
Intuition
If we can modify the node values, we can mark each visited node with a special value (outside the problem's constraints). If we encounter a node already marked with that value, it's the start of the cycle.
Detailed Dry Run
List: 3 -> 2 -> 0 -> -4 (back to 2).
⚠️ Common Pitfalls & Tips
This modifies the original list. In many real-world or interview scenarios, modifying the input data is not allowed unless specified.
Intuition
Detect cycle first, then reset one pointer to head and move both at speed 1 to find meeting point.
D = Distance to cycle, S = Meeting point from start, C = Cycle length.
Moving D steps from head and D steps from meeting point hits cycle start.Remove Linked List Elements
Remove all nodes of the linked list that has Node.val == val.
List: 1 -> 6 -> 2, val = 6
Result: 1 -> 2Examples
Intuition
Use a dummy node to handle head removal. Traverse and skip nodes matching val.
Intuition
Process the rest of the list first. If the current head's value matches the target, return the processed rest; otherwise, link the current head to the processed rest and return the head.
Detailed Dry Run
remove(1->6->2, 6).
Odd Even Linked List
Group nodes with odd indices together followed by even indices.
1 -> 2 -> 3 -> 4 -> 5
Odd: 1 -> 3 -> 5
Even: 2 -> 4
Result: 1 -> 3 -> 5 -> 2 -> 4Examples
Intuition
Traverse the list and store odd-indexed nodes in one list/array and even-indexed nodes in another. Then, link the end of the odd list to the head of the even list.
Detailed Dry Run
1->2->3->4. Odd: [1, 3]. Even: [2, 4]. Result: 1->3->2->4.
Intuition
Maintain odd and even pointers, cross-linking as you traverse.
Swap Nodes in Pairs
Swap every two adjacent nodes.
1 -> 2 -> 3 -> 4
Result: 2 -> 1 -> 4 -> 3Examples
Intuition
Swap first two nodes, recurse for the rest.
Intuition
Use a dummy node to simplify head swapping. Use a prev pointer to track the node before the current pair being swapped.
Detailed Dry Run
Dummy -> 1 -> 2 -> 3 -> 4. Prev = Dummy.
Rotate List
Rotate the list to the right by k places.
1 -> 2 -> 3 -> 4 -> 5, k = 2
Output: 4 -> 5 -> 1 -> 2 -> 3Intuition
Form a cycle, find the new tail (n-k%n), and break.
Intuition
Use two pointers, first and second. Move first k steps ahead. Then move both until first reaches the end. second will then be at the node before the new head.
Detailed Dry Run
1->2->3->4->5, k=2.
Convert Sorted List to BST
Convert a sorted linked list to a height-balanced BST.
List: -10 -> -3 -> 0 -> 5 -> 9
Root is 0.Intuition
Convert the linked list into an array. Then, use a standard recursive algorithm to convert the sorted array into a height-balanced BST by picking the middle element as the root.
Detailed Dry Run
List: -10, -3, 0, 5, 9. Array: [-10, -3, 0, 5, 9].
Intuition
Use slow/fast pointers to find the middle (root), split, and recurse.
Help us improve! Report bugs or suggest new features on our Telegram group.