Bird
Raised Fist0
Interview Preplinked-list-advancedmediumAmazonGoogleMicrosoft

Design Linked List (Full Implementation)

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Initialize dummy head, tail, and size

Create a dummy head node with value 0 and no next node. Set tail pointer to dummy and size counter to 0.

💡 Dummy head simplifies edge cases by providing a fixed start; tail pointer helps efficient tail insertions; size tracks list length for quick index validation.
Line:self.dummy = Node(0) self.tail = self.dummy self.size = 0
💡 The linked list starts empty but ready for operations with dummy and tail pointers set.
📊
Design Linked List (Full Implementation) - Watch the Algorithm Execute, Step by Step
Watching each pointer move and node change live helps you understand how linked list operations work internally, beyond just reading code.
Step 1/24
·Active fillAnswer cell
setup
0
insert
0
1
connect
0
1
connect
0
1
advance
0
1
insert
0
1
3
connect
0
1
3
advance
0
1
3
advance
0
1
3
compare
0
1
3
advance
0
1
3
insert
0
1
3
2
connect
0
1
3
2
advance
0
1
3
2
compare
0
1
3
2
advance
0
1
3
2
compare
0
1
3
2
Result: 2
compare
0
1
3
2
Result: 2
advance
0
1
3
2
Result: 2
detach
0
1
3
Result: 2
shrink
0
1
3
Result: 2
compare
0
1
3
Result: 2
advance
0
1
3
Result: 2
compare
0
1
3
Result: 3

Key Takeaways

Using a dummy head node simplifies edge cases for insertions and deletions at the head.

Without dummy, special code is needed for head operations; dummy unifies logic.

Maintaining a tail pointer allows O(1) insertions at the tail without traversal.

Without tail pointer, adding at tail requires traversing entire list, which is inefficient.

Tracking size enables immediate index validity checks, preventing unnecessary traversal.

Size check quickly rejects invalid indices, saving time and avoiding errors.

Practice

(1/5)
1. You need to implement a browser history feature that supports visiting new URLs, moving backward by a number of steps, and moving forward by a number of steps. Which data structure approach best supports efficient visit, back, and forward operations with minimal time complexity?
easy
A. Using a single list with an index pointer to track the current page, slicing the list on visits to discard forward history.
B. Using a queue to store all visited URLs and dequeuing when moving back or forward.
C. Using a doubly linked list where each node stores a URL and pointers to previous and next pages.
D. Using two stacks: one for back history and one for forward history, pushing and popping URLs as navigation occurs.

Solution

  1. Step 1: Understand operation requirements

    Visit must discard forward history, back and forward must move efficiently without scanning the entire history.
  2. Step 2: Evaluate data structures

    Two stacks allow O(1) amortized push/pop for visit, back, and forward, efficiently managing history and forward pages.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Two stacks handle forward/back navigation efficiently [OK]
Hint: Two stacks efficiently manage back and forward navigation [OK]
Common Mistakes:
  • Using a single list with slicing causes O(n) visit time
  • Doubly linked list is correct but more complex
  • Queue does not support backward navigation efficiently
2. You are given a singly linked list and a value x. The task is to reorder the list so that all nodes with values less than x come before nodes with values greater than or equal to x, while preserving the original relative order within each partition. Which approach guarantees an optimal solution with O(n) time and O(1) space complexity?
easy
A. Extract all node values into arrays, reorder them, then rebuild the list.
B. Use two pointers to build two separate linked lists for nodes less than and greater or equal to x, then concatenate them.
C. Sort the entire linked list using merge sort and then split at value x.
D. Traverse the list once, rearranging nodes in-place by adjusting pointers without extra lists.

Solution

  1. Step 1: Understand the problem constraints

    The problem requires partitioning the list around value x while preserving relative order and achieving O(n) time and O(1) space.
  2. Step 2: Evaluate approaches

    Approach A uses extra arrays, so space is O(n). Approach B uses extra lists, so space is O(n). Approach D sorts the list, which is O(n log n) time. Only approach C rearranges nodes in-place in one pass with constant space.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    In-place rearrangement achieves O(n) time and O(1) space [OK]
Hint: In-place pointer rearrangement is O(1) space [OK]
Common Mistakes:
  • Assuming sorting is needed to partition
  • Using extra arrays or lists increases space
  • Believing two separate lists always use constant space
3. Identify the bug in the following code snippet implementing the optimal approach to copy a list with random pointers:
medium
A. Line assigning curr.next.random = curr.random.next misses null check for curr.random
B. In Step 3, copy_curr is never advanced, causing incorrect separation
C. In Step 1, new_node is linked incorrectly to curr.next
D. The function returns copy_head before fully separating the lists

Solution

  1. Step 1: Analyze Step 3 separation loop

    copy_curr is initialized but never advanced inside the loop, so copied list links are not updated correctly.
  2. Step 2: Identify fix

    Adding copy_curr = copy_curr.next inside the loop after updating copy_curr.next fixes the bug.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Without advancing copy_curr, copied list remains partially linked [OK]
Hint: Check if both original and copy pointers advance in separation loop [OK]
Common Mistakes:
  • Forgetting to advance copy_curr in separation
  • Assuming random pointer null checks are missing (they are present)
  • Mislinking new_node in Step 1 (correct here)
4. What is the space complexity of the recursive reorder list approach that uses a helper function with recursion to reorder the list in place?
medium
A. O(n) -- recursion stack uses space proportional to list length
B. O(1) -- only constant extra pointers used
C. O(log n) -- recursion depth is halved each call
D. O(n^2) -- due to repeated pointer updates in recursion

Solution

  1. Step 1: Identify recursion depth

    The helper function recurses once per node, so recursion depth is n.
  2. Step 2: Calculate space usage

    Each recursive call adds stack frame, so total space is O(n), not constant or logarithmic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Recursion stack proportional to list length [OK]
Hint: Recursion depth equals list length -> O(n) space [OK]
Common Mistakes:
  • Assuming constant space due to in-place changes
  • Confusing recursion depth with log n
  • Overestimating to quadratic space
5. Suppose the partition problem is modified so that nodes can be reused multiple times (e.g., the list represents a multiset with unlimited copies). Which modification to the optimal in-place partition algorithm correctly handles this scenario without breaking the algorithm?
hard
A. Convert the list to arrays, partition values, then rebuild the list to handle duplicates safely.
B. Use the same in-place pointer rearrangement but skip nodes already processed to avoid infinite loops.
C. Modify the algorithm to clone nodes when moving them to the less-than-x partition to preserve original nodes.
D. Use two separate lists with dummy heads and append clones of nodes to handle reuse.

Solution

  1. Step 1: Understand the reuse constraint

    Nodes can be reused multiple times, so in-place rearrangement that moves nodes breaks because nodes are unique objects.
  2. Step 2: Evaluate modifications

    In-place rearrangement cannot handle duplicates without cloning. Cloning in-place is complex and error-prone. Using arrays to store values and rebuild the list handles duplicates safely and cleanly.
  3. Step 3: Compare cloning approaches

    Cloning nodes in-place or in two lists adds complexity and risks pointer errors. Arrays simplify the problem.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Rebuilding from arrays safely handles duplicates and reuse [OK]
Hint: Rebuild list from arrays to handle node reuse safely [OK]
Common Mistakes:
  • Trying to rearrange nodes in-place with reuse
  • Cloning nodes without updating pointers correctly
  • Assuming pointer moves work with reused nodes