Design solutions conceptually (no code) while adhering to specific time/space complexities.
Problem: Determine if a singly linked list has a cycle (a node points to a previous node).
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Use Floyd’s Tortoise and Hare algorithm:
Initialize two pointers: slow
(moves 1 node/step) and fast
(moves 2 nodes/step).
Traverse the list. If fast
meets slow
, a cycle exists.
If fast
reaches null
, no cycle exists.
Why O(1) space? Only two pointers are used, regardless of list size.
Problem: Sort a stack in ascending order using only one temporary stack.
Constraints:
Time: O(n²)
Space: O(n) (for the temporary stack)
Solution Approach:
Use the primary stack for input and the temporary stack for sorted output.
While the primary stack is not empty:
Pop the top element temp
from the primary stack.
Move all elements greater than temp
from the temporary stack back to the primary stack.
Push temp
into the temporary stack.
The temporary stack will hold sorted elements.
Why O(n²) time? Each element may require multiple transfers between stacks.
Problem: Reverse the order of elements in a queue.
Constraints:
Time: O(n)
Space: O(n)
Solution Approach:
Dequeue all elements from the queue and push them onto a stack.
Pop elements from the stack and enqueue them back into the original queue.
Result: The queue is reversed.
Why O(n) space? The stack temporarily stores all n
elements.
Problem: Identify the middle node of a singly linked list without knowing its length.
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Use the two-pointer technique:
Initialize slow
and fast
pointers at the head.
Move slow
by 1 node and fast
by 2 nodes per step.
When fast
reaches the end, slow
will be at the middle.
Why O(n) time? The list is traversed once.
Problem: Determine if a string of parentheses (){}[]
is balanced.
Constraints:
Time: O(n)
Space: O(n)
Solution Approach:
Use a stack to track opening brackets.
For each character in the string:
If it’s an opening bracket, push it onto the stack.
If it’s a closing bracket, check if it matches the top of the stack.
If yes, pop the stack.
If no, return false
.
The string is balanced if the stack is empty at the end.
Why O(n) space? In the worst case (all opening brackets), the stack holds n
elements.
Problem: Design a queue where enqueue
and dequeue
operations meet amortized O(1) time.
Constraints:
Time: O(1) amortized for both operations.
Space: O(n)
Solution Approach:
Use two stacks: stack1
for enqueue, stack2
for dequeue.
Enqueue: Push elements into stack1
(O(1)).
Dequeue:
If stack2
is empty, transfer all elements from stack1
to stack2
(reversing order).
Pop from stack2
(O(1) amortized, as each element is moved once).
Key Takeaways:
Linked Lists: Two-pointer techniques optimize traversal and detection.
Stacks/Queues: Use auxiliary stacks/queues to rearrange elements efficiently.
Space Constraints: Often trade time for space (e.g., stacks for reversing queues).
Thought for 14 seconds
Design solutions conceptually (no code) while adhering to specific time/space complexities.
Problem: Remove the Nth node from the end of a singly linked list in one pass.
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Use two pointers: fast
and slow
.
Move fast
N nodes ahead of slow
.
Traverse the list until fast
reaches the end.
The slow
pointer will be at the node just before the target. Remove the target node.
Key Insight: The gap between fast
and slow
ensures slow
stops at the correct position.
Problem: Design a stack that supports push
, pop
, and getMin
(retrieve the minimum element) in O(1) time for all operations.
Constraints:
Time: O(1) per operation.
Space: O(n).
Solution Approach:
Use two stacks:
Main stack for elements.
Auxiliary stack to track the current minimum.
Push:
Add the element to the main stack.
If the element ≤ current minimum (from auxiliary stack), push it to the auxiliary stack.
Pop:
Remove from the main stack.
If the popped element equals the top of the auxiliary stack, pop the auxiliary stack.
getMin: Return the top of the auxiliary stack.
Problem: Generate binary numbers from 1 to N using a queue.
Constraints:
Time: O(n)
Space: O(n)
Solution Approach:
Initialize the queue with "1".
For each iteration:
Dequeue the front element.
Append "0" and "1" to create the next two binary numbers.
Enqueue these new numbers.
Repeat until N numbers are generated.
Example:
Queue starts with "1".
For N=3: "1" → "10", "11" → "100", "101", "110", "111".
Problem: Determine if a singly linked list is a palindrome.
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Use two pointers to find the middle of the list.
Reverse the second half of the list.
Compare the first half with the reversed second half.
Restore the reversed half (optional).
Why O(1) space? Reversing in-place avoids using extra memory.
Problem: Evaluate a postfix expression (e.g., 3 4 + 2 *
= 14) using a stack.
Constraints:
Time: O(n)
Space: O(n)
Solution Approach:
Traverse the expression left to right.
For each token:
If it’s a number, push to the stack.
If it’s an operator, pop two operands, compute the result, and push the result back.
The final value in the stack is the result.
Example:
3 4 + 2
→ Stack: [3] → [3,4] → pop 3,4 → 3+4=7 → push 7 → push 2 → pop 7,2 → 72=14.
Problem: Reverse the order of the first K elements in a queue.
Constraints:
Time: O(n)
Space: O(K) (use a stack for reversal).
Solution Approach:
Dequeue the first K elements and push them onto a stack.
Pop elements from the stack and enqueue them back (reversing the first K).
Dequeue the remaining n-K elements and enqueue them back in original order.
Example:
Queue: [1,2,3,4,5], K=3 → Stack: [1,2,3] → Reversed: [3,2,1] → Queue becomes [3,2,1,4,5].
Problem: Flatten a multilevel linked list (nodes may have child pointers) into a single-level list.
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Traverse the list. When a node with a child is found:
Merge the child list into the main list.
Adjust pointers to skip the child hierarchy.
Use depth-first traversal to prioritize child nodes.
Visualization:
Input: 1 → 2 → 3 → 4
︲5 → 6
Output: 1 → 2 → 5 → 6 → 3 → 4
.
Problem: Simulate browser history (back/forward navigation) using two stacks.
Constraints:
Time: O(1) for visit
, back
, and forward
operations.
Space: O(n).
Solution Approach:
Main Stack: Stores visited pages in chronological order.
Forward Stack: Temporarily stores pages when moving back.
Visit: Clear the forward stack, push the new page to the main stack.
Back: Pop from the main stack and push to the forward stack.
Forward: Pop from the forward stack and push to the main stack.
Key Takeaways:
Linked Lists: Leverage pointer manipulation and traversal techniques.
Stacks/Queues: Use auxiliary structures to rearrange elements efficiently.
Time vs. Space Trade-offs: Optimize for constraints (e.g., reversing queues with stacks).
Thought for 24 seconds
Design solutions conceptually (no code) while adhering to specific time/space complexities.
Problem: Merge two sorted singly linked lists into one sorted list.
Constraints:
Time: O(n + m) (where nn and mm are the lengths of the two lists).
Space: O(1) (reuse existing nodes, no new data structures).
Solution Approach:
Use a dummy node to simplify edge cases (e.g., empty lists).
Compare nodes from both lists, appending the smaller value to the merged list.
Advance the pointer of the list from which the node was taken.
Continue until both lists are exhausted.
Key Insight: Reassign pointers in-place to avoid extra memory.
Problem: Given two sequences pushed
and popped
, determine if they represent valid operations on an initially empty stack.
Constraints:
Time: O(n)
Space: O(n) (for simulating the stack).
Solution Approach:
Simulate the stack:
Push elements from pushed
in order.
Whenever the top of the stack matches the current popped
element, pop it.
If the stack is empty after processing all elements, the sequences are valid.
Example:
pushed = [1,2,3,4,5]
, popped = [4,5,3,2,1]
→ Valid.
popped = [4,3,5,1,2]
→ Invalid (1 cannot be popped before 2).
Problem: Design a circular queue with a fixed size KK that supports enqueue
, dequeue
, and isEmpty
operations.
Constraints:
Time: O(1) for all operations.
Space: O(K) (fixed-size array).
Solution Approach:
Use an array of size KK and two pointers: front
(points to the first element) and rear
(points to the next empty slot).
Enqueue:
Check if the queue is full using (rear + 1) % K == front
.
Insert at rear
and update rear = (rear + 1) % K
.
Dequeue:
Remove the element at front
and update front = (front + 1) % K
.
Edge Case: Handle wrap-around using modulo arithmetic.
Problem: Remove all duplicates from a sorted singly linked list, leaving only distinct values.
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Traverse the list with a pointer current
.
For each node, check if its value equals the next node’s value.
If duplicates exist, skip all duplicate nodes by adjusting pointers.
Example:
Input: 1 → 1 → 2 → 3 → 3
Output: 1 → 2 → 3
Problem: Given an array of heights representing a histogram, find the area of the largest rectangle.
Constraints:
Time: O(n)
Space: O(n) (for tracking indices and heights).
Solution Approach:
Use a stack to track indices of bars in increasing order of height.
For each bar:
Pop from the stack while the current bar’s height is less than the stack’s top.
Calculate the area using the popped index as the height and the distance between the current index and the new stack top as the width.
Update the maximum area during each calculation.
Key Insight: The stack maintains the "last smaller bar" for efficient area computation.
Problem: Interleave the first half of a queue with the second half.
Constraints:
Time: O(n)
Space: O(n) (use a stack/queue for temporary storage).
Solution Approach:
Split the queue into two halves using a stack or temporary queue.
Re-insert elements by alternating between the first and second halves.
Example:
Input: [1,2,3,4,5,6]
→ Split into [1,2,3]
and [4,5,6]
.
Output: [1,4,2,5,3,6]
.
Problem: Rotate a linked list to the right by KK positions.
Constraints:
Time: O(n)
Space: O(1)
Solution Approach:
Compute the effective rotation Keff=K%nKeff=K%n (avoids redundant rotations).
Use two pointers to find the new tail and head:
Traverse to the (n−Keff)(n−Keff)th node.
Set this node as the new tail and link the original tail to the original head.
Example:
Input: 1 → 2 → 3 → 4 → 5
, K=2K=2 → Output: 4 → 5 → 1 → 2 → 3
.
Problem: Convert an absolute Unix-style file path (e.g., /a/./b/../c/
) to its canonical form.
Constraints:
Time: O(n)
Space: O(n) (split path into components).
Solution Approach:
Split the path by /
and process each component:
Ignore .
and empty strings.
Pop from the stack on ..
.
Push valid directory names onto the stack.
Join the stack to form the canonical path.
Example:
/a/./b/../c/
→ Stack: ["a", "c"]
→ Canonical path: /a/c
.
Problem: Implement a RecentCounter
that counts the number of requests in the last 3000 milliseconds.
Constraints:
Time: O(1) amortized for ping()
.
Space: O(n) (store timestamps in a queue).
Solution Approach:
Use a queue to store timestamps.
For each new ping(t)
, remove all timestamps older than t−3000t−3000 from the front of the queue.
Add tt to the queue and return its length.
Example:
ping(1) → 1
, ping(3002) → 2
(since 3002 - 3000 = 2 > 1).
Key Takeaways:
Linked Lists: Focus on pointer manipulation and traversal patterns (e.g., two-pointer, in-place reversal).
Stacks: Leverage LIFO order for problems involving nested structures or backtracking (e.g., parentheses, histograms).
Queues: Use FIFO order for sequence-based operations (e.g., interleaving, sliding windows).
Space-Time Trade-offs: Optimize for constraints (e.g., circular queues for fixed-space efficiency).