Bird
Raised Fist0
Interview Prepin-place-linked-listmediumAmazonFacebook

Remove Duplicates from Sorted List II

Choose your preparation mode4 modes available
▶
Steps
setup

Initialize head pointer at first node

The algorithm starts with the head pointer at the first node with value 1. It checks if the list is empty or has only one node.

💡 This step sets the starting point for recursion and handles base cases.
Line:if not head or not head.next: return head
💡 Base case check ensures recursion stops at list end or single node.
📊
Remove Duplicates from Sorted List II - Watch the Algorithm Execute, Step by Step
Watching each pointer move and recursive call helps you understand how duplicates are skipped entirely and how the list is reconstructed without duplicates.
Step 1/15
·Active fill★Answer cell
advance
1
→
2
→
3
→
3
→
4
→
4
→
5
compare
1
→
2
→
3
→
3
→
4
→
4
→
5
traverse
1
→
2
→
3
→
3
→
4
→
4
→
5
compare
1
→
2
→
3
→
3
→
4
→
4
→
5
traverse
2
→
3
→
3
→
4
→
4
→
5
compare
3
→
3
→
4
→
4
→
5
shrink
4
→
4
→
5
traverse
4
→
4
→
5
compare
4
→
4
→
5
shrink
5
compare
5
reconstruct
5
reconstruct
2
→
5
reconstruct
1
→
2
→
5
advance
1
→
2
→
5
Result: [1,2,5]

Key Takeaways

✓ The algorithm removes all nodes with duplicate values entirely, not just extra copies.

Reading code alone can confuse whether duplicates are removed or just reduced; visualization clarifies complete removal.

✓ Recursion breaks the problem into smaller sublists, making it easier to handle duplicates locally and reconstruct the list cleanly.

Understanding recursion flow is hard without seeing how each recursive call processes a sublist.

✓ Pointer skipping inside the while loop efficiently removes all duplicates of a value in one go.

Visualizing pointer moves shows how the algorithm jumps over duplicates instead of removing nodes one by one.

Practice

(1/5)
1. You are given a singly linked list and asked to reverse it in-place, such that the last node becomes the head and all pointers are reversed. Which approach guarantees an optimal solution with O(n) time and O(n) space complexity, avoiding stack overflow on large inputs?
easy
A. Use a brute force recursive reversal that reverses pointers on the way back up the call stack.
B. Use dynamic programming to store reversed sublists and combine them to form the reversed list.
C. Use a greedy approach that swaps node values instead of pointers to reverse the list.
D. Use a tail-recursive helper function that passes previous and current nodes, reversing pointers during the recursive descent.

Solution

  1. Step 1: Understand the problem constraints

    The problem requires reversing a singly linked list in-place, which means changing the next pointers without extra data structures.
  2. Step 2: Evaluate approaches

    The brute force recursive reversal (A) uses recursion but reverses pointers on the return path, risking stack overflow and extra space. The greedy approach (C) swaps values, which is not pointer reversal and may not be allowed. Dynamic programming (D) is not applicable here. The tail-recursive helper function (B) reverses pointers during recursion descent, maintaining O(n) time and O(n) space due to recursion stack, and is optimal.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Tail recursion with prev and curr pointers ensures correct reversal [OK]
Hint: Tail recursion reverses pointers during descent [OK]
Common Mistakes:
  • Confusing value swapping with pointer reversal
  • Using naive recursion causing stack overflow
2. What is the time complexity of the two-pointer length equalization approach to find the intersection node of two singly linked lists with lengths m and n, respectively?
medium
A. O(m + n)
B. O(m * n)
C. O(max(m, n) * 2)
D. O(m + n + k), where k is the length of the intersection

Solution

  1. Step 1: Identify loop iterations

    Each pointer traverses its list once, then switches to the other list, traversing at most m + n nodes.
  2. Step 2: Simplify complexity

    Total steps are proportional to m + n, so time complexity is O(m + n). O(m * n) is brute force, O(max(m, n) * 2) simplifies to O(m + n), and O(m + n + k) adds an unnecessary term.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Two-pointer approach is linear in combined list lengths [OK]
Hint: Pointers traverse each list once plus switch [OK]
Common Mistakes:
  • Confusing nested loops with two-pointer approach
  • Counting intersection length separately
  • Misreading max(m,n) as multiplication
3. What is the time complexity of the optimal min-heap based algorithm for merging k sorted linked lists with a total of N nodes?
medium
A. O(N k) because each node is compared with nodes from all k lists.
B. O(N log N) because all nodes are pushed and popped from the heap.
C. O(kN) because each list is merged sequentially with all others.
D. O(N log k) because each of the N nodes is pushed and popped from a heap of size at most k.

Solution

  1. Step 1: Identify heap operations per node

    Each node is pushed and popped exactly once from a heap of size ≤ k.
  2. Step 2: Calculate complexity

    Heap push/pop cost is O(log k), total O(N log k) for N nodes.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Heap size depends on k, not N, so O(N log k) [OK]
Hint: Heap size is k, not N, so complexity is O(N log k) [OK]
Common Mistakes:
  • Confusing N and k in log factor
  • Assuming heap size grows with N
  • Thinking sequential merges are optimal
4. Suppose the problem is modified so that if the number of nodes remaining is less than k, you must reverse them as well (i.e., reverse all nodes in the last group regardless of size). Which modification to the optimal iterative approach correctly implements this?
hard
A. Use the original approach but after the main loop, reverse the remaining nodes by calling reverseLinkedList on group_prev.next with the remaining count.
B. Remove the check for group size before reversal and always reverse k nodes; for the last group, reverse whatever nodes remain.
C. Modify the inner while loop to count nodes until the end, then reverse the last group if count < k after the loop ends.
D. Keep the check for k nodes but add a separate recursive call to reverse the last partial group after the main loop.

Solution

  1. Step 1: Identify how to handle the last partial group

    The original loop breaks if fewer than k nodes remain, so the last partial group is untouched.
  2. Step 2: Reverse the last partial group after the main loop

    After the loop, call reverseLinkedList on group_prev.next with the remaining node count to reverse the last group.
  3. Step 3: Why other options fail

    Removing the check causes incorrect reversal attempts; recursive calls add unnecessary complexity; modifying inner loop breaks group boundaries.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Post-loop reversal of leftover nodes correctly handles last partial group [OK]
Hint: Reverse leftover nodes after main loop to handle partial group [OK]
Common Mistakes:
  • Removing group size check causes invalid reversals
  • Trying to reverse partial group inside main loop breaks logic
5. Suppose the problem is modified so that the linked list is circular (the last node points back to the head). Which of the following modifications to the recursive swapPairs function correctly handles swapping nodes in pairs without causing infinite recursion or losing nodes?
hard
A. Modify the base case to stop recursion when the next node is the head, breaking the cycle.
B. Add a visited set to track nodes and stop recursion when a node repeats.
C. Use the same recursive approach without changes; it naturally terminates on circular lists.
D. Convert the circular list to a linear list by breaking the cycle before swapping.

Solution

  1. Step 1: Understand circular list implications

    In a circular list, naive recursion never reaches a null node, causing infinite recursion.
  2. Step 2: Modify base case to detect cycle

    Stopping recursion when next node is the head prevents infinite loops and preserves all nodes.
  3. Step 3: Compare alternatives

    Using a visited set adds overhead; breaking cycle beforehand changes problem constraints; naive recursion fails.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Base case adjusted for cycle detection prevents infinite recursion [OK]
Hint: Detect cycle in base case to stop recursion [OK]
Common Mistakes:
  • Ignoring cycle causes infinite recursion
  • Trying naive recursion without cycle check
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard