Add stack-queue module: ten stack and queue interview problems, monotonic stack, min stack, queue from stacks and stack from a queue, brute-force cross-checks, dry-run traces, operation counts, pitfalls (11 tests)

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b6nxynun5JFivebVb1
This commit is contained in:
Claude
2026-11-12 22:35:43 +05:30
parent c5c435ae20
commit b9aeb78b24
36 changed files with 2164 additions and 0 deletions
@@ -0,0 +1,28 @@
Balanced brackets: every step of four inputs
============================================
input: {[()]} firstMismatch = -1
read '{' at 0: push '}' waiting for (top first): }
read '[' at 1: push ']' waiting for (top first): ] }
read '(' at 2: push ')' waiting for (top first): ) ] }
read ')' at 3: pop ')', matches waiting for (top first): ] }
read ']' at 4: pop ']', matches waiting for (top first): }
read '}' at 5: pop '}', matches waiting for (top first): (empty)
end of input: waiting for (empty) -> balanced
input: ([)] firstMismatch = 2
read '(' at 0: push ')' waiting for (top first): )
read '[' at 1: push ']' waiting for (top first): ] )
read ')' at 2: expected ']' -> NOT balanced
input: ()) firstMismatch = 2
read '(' at 0: push ')' waiting for (top first): )
read ')' at 1: pop ')', matches waiting for (top first): (empty)
read ')' at 2: stack is empty, nothing to close -> NOT balanced
input: (() firstMismatch = 0
read '(' at 0: push ')' waiting for (top first): )
read '(' at 1: push ')' waiting for (top first): ) )
read ')' at 2: pop ')', matches waiting for (top first): )
end of input: waiting for ) -> NOT balanced, openers left over
+17
View File
@@ -0,0 +1,17 @@
Reverse Polish Notation: stack after every token
================================================
tokens: [2, 1, +, 3, *] result = 9
token 2: push 2 stack(top first) = [2]
token 1: push 1 stack(top first) = [1, 2]
token +: pop 1 then 2, compute 2 + 1 = 3 stack(top first) = [3]
token 3: push 3 stack(top first) = [3, 3]
token *: pop 3 then 3, compute 3 * 3 = 9 stack(top first) = [9]
tokens: [4, 13, 5, /, +] result = 6
token 4: push 4 stack(top first) = [4]
token 13: push 13 stack(top first) = [13, 4]
token 5: push 5 stack(top first) = [5, 13, 4]
token /: pop 5 then 13, compute 13 / 5 = 2 stack(top first) = [2, 4]
token +: pop 2 then 4, compute 4 + 2 = 6 stack(top first) = [6]
+16
View File
@@ -0,0 +1,16 @@
Min stack: both internal stacks after every operation
=====================================================
push 5 values=[5] mins=[5] (new or equal minimum, also pushed on mins)
push 3 values=[3, 5] mins=[3, 5] (new or equal minimum, also pushed on mins)
push 7 values=[7, 3, 5] mins=[3, 5]
push 3 values=[3, 7, 3, 5] mins=[3, 3, 5] (new or equal minimum, also pushed on mins)
getMin values=[3, 7, 3, 5] mins=[3, 3, 5] getMin() = 3
pop -> 3 values=[7, 3, 5] mins=[3, 5] (it was the minimum, mins popped too)
getMin values=[7, 3, 5] mins=[3, 5] getMin() = 3
pop -> 7 values=[3, 5] mins=[3, 5]
getMin values=[3, 5] mins=[3, 5] getMin() = 3
pop -> 3 values=[5] mins=[5] (it was the minimum, mins popped too)
getMin values=[5] mins=[5] getMin() = 5
getMin results: [3, 3, 3, 5] (identical for MinStack and EncodedMinStack)
@@ -0,0 +1,17 @@
Next greater element: the stack of pending indices, step by step
================================================================
input [2, 1, 2, 4, 3]
i=0 value=2: push 0 pending(top first) = [0]
i=1 value=1: push 1 pending(top first) = [1, 0]
i=2 value=2: pop index 1 (value 1) -> its answer is 2; push 2 pending(top first) = [2, 0]
i=3 value=4: pop index 2 (value 2) -> its answer is 4; pop index 0 (value 2) -> its answer is 4; push 3 pending(top first) = [3]
i=4 value=3: push 4 pending(top first) = [4, 3]
indices still pending have no greater element to their right: [4, 3] -> stay -1
result [4, 2, 4, -1, -1]
dailyTemperatures [73, 74, 75, 71, 69, 72, 76, 73]
= [1, 1, 4, 2, 1, 1, 0, 0]
nextGreaterCircular [1, 2, 1] = [2, -1, 2]
nextGreaterSubset [4, 1, 2] within [1, 3, 4, 2] = [-1, 3, -1]
+25
View File
@@ -0,0 +1,25 @@
Largest rectangle in a histogram: pops, widths and areas
========================================================
heights [2, 1, 5, 6, 2, 3]
i=0 height=2:
push index 0 stack(top first) = [0]
i=1 height=1:
pop bar of height 2: left edge index -1, right edge index 0, width 1, area 2 best = 2
push index 1 stack(top first) = [1]
i=2 height=5:
push index 2 stack(top first) = [2, 1]
i=3 height=6:
push index 3 stack(top first) = [3, 2, 1]
i=4 height=2:
pop bar of height 6: left edge index 2, right edge index 3, width 1, area 6 best = 6
pop bar of height 5: left edge index 1, right edge index 3, width 2, area 10 best = 10
push index 4 stack(top first) = [4, 1]
i=5 height=3:
push index 5 stack(top first) = [5, 4, 1]
i=6 (sentinel) height=0:
pop bar of height 3: left edge index 4, right edge index 5, width 1, area 3 best = 10
pop bar of height 2: left edge index 1, right edge index 5, width 4, area 8 best = 10
pop bar of height 1: left edge index -1, right edge index 5, width 6, area 6 best = 10
push index 6 stack(top first) = [6]
largest rectangle = 10
@@ -0,0 +1,16 @@
Queue from two stacks, and stack from one queue
===============================================
QueueViaStacks (stacks shown top first)
enqueue(1) in=[1] out=[]
enqueue(2) in=[2, 1] out=[]
enqueue(3) in=[3, 2, 1] out=[]
dequeue() = 1 in=[] out=[2, 3] transfers so far: 3
enqueue(4) in=[4] out=[2, 3]
dequeue() x3 = 2, 3, 4 in=[] out=[] transfers so far: 4
StackViaQueue
push(1) queue(front=top)=[1] rotations so far: 0
push(2) queue(front=top)=[2, 1] rotations so far: 1
push(3) queue(front=top)=[3, 2, 1] rotations so far: 3
pop() x2 = 3, 2 queue(front=top)=[1]
+13
View File
@@ -0,0 +1,13 @@
All ten problems on their headline examples
===========================================
1. isBalanced("{[()]}") = true; isBalanced("([)]") = false
2. evaluate([2, 1, +, 3, *]) = 9; 7 / -3 truncates toward zero: -2
3. push -2, 0, -3: getMin = -3; pop; top = 0, getMin = -2 (both implementations agree)
4. nextGreater([1, 3, 4, 2]) = [3, 4, -1, -1]
5. dailyTemperatures([73, 74, 75, 71, 69, 72, 76, 73]) = [1, 1, 4, 2, 1, 1, 0, 0]
6. nextGreaterCircular([1, 2, 3, 4, 3]) = [2, 3, 4, -1, 4]
7. largestRectangle([2, 1, 5, 6, 2, 3]) = 10
8. decode("3[a2[bc]]") = "abcbcabcbcabcbc"; decode("2[abc]3[cd]ef") = "abcabccdcdcdef"
9. enqueue a, b, c; dequeue = a; enqueue d; dequeue = b; peek = c; size = 2
10. push a, b, c; top = c; pop = c; pop = b; size = 1
@@ -0,0 +1,12 @@
Random agreement with brute force (seed 20261112, 5000 cases per row)
=====================================================================
nextGreater vs scan-right 5000 cases, 0 mismatches
dailyTemperatures vs scan-right 5000 cases, 0 mismatches
nextGreaterCircular vs wrap-around scan 5000 cases, 0 mismatches
largestRectangle vs widen-each-bar 5000 cases, 0 mismatches
isBalanced vs delete-adjacent-pairs 5000 cases, 0 mismatches
decode vs recursive descent 5000 cases, 0 mismatches
evaluate (RPN) vs expression-tree evaluation 5000 cases, 0 mismatches
MinStack and EncodedMinStack vs recompute-the-min 5000 sequences (150000 operations), 0 mismatches
QueueViaStacks and StackViaQueue vs ArrayDeque 5000 sequences (150000 operations), 0 mismatches
@@ -0,0 +1,24 @@
Operation counts (counted, not timed)
=====================================
nextGreater on a strictly decreasing array (the worst case for the scan-right version)
n scan-right compares stack compares stack push+pop
1000 499500 999 1000
10000 49995000 9999 10000
100000 4999950000 99999 100000
nextGreater on random values (n = 100000): every index is pushed once and popped at most once
pushes = 100000, pops = 99985, comparisons = 199977 (bound: comparisons <= 2n = 200000)
QueueViaStacks: n enqueues followed by n dequeues
n total element moves moves in the 1st dequeue
1000 1000 1000
10000 10000 10000
100000 100000 100000
one dequeue can cost n moves, but each element moves exactly once, so n enqueues + n dequeues cost 3n steps in all
StackViaQueue: n pushes
n total rotations n(n-1)/2
100 4950 4950
1000 499500 499500
5000 12497500 12497500
@@ -0,0 +1,19 @@
java.util.Stack versus ArrayDeque used as a stack
=================================================
ArrayDeque as a stack: push(1), push(2), push(3), then pop until empty -> [3, 2, 1]
ArrayDeque as a queue: offer(1), offer(2), offer(3), then poll until empty -> [1, 2, 3]
push(1), push(2), push(3), then iterate:
java.util.Stack -> [1, 2, 3] (bottom to top)
ArrayDeque -> [3, 2, 1] (top to bottom)
Stack.class.getSuperclass() = java.util.Vector
Stack.pop() is synchronized = true
ArrayDeque.pop() is synchronized = false
push(null) on Stack = accepted
push(null) on ArrayDeque = java.lang.NullPointerException
ArrayDeque: push(1), push(2), peek() = 2 (push is addFirst)
ArrayDeque: offer(1), offer(2), peek() = 1 (offer is addLast)
+33
View File
@@ -0,0 +1,33 @@
Eight classic mistakes, each reproduced
=======================================
1. balanced brackets by counting each kind, with no stack
input "([)]": counts-only = true stack = false
every count ends at zero, but the ] arrives while the ( is not the innermost open bracket
2. min stack that compares boxed Integers with ==
push [10, 20, 5], pop, getMin(): broken = 10 correct = 10
push [1000, 2000, 500], pop, getMin(): broken = 500 correct = 1000
Integer.valueOf caches -128..127, so small values share one object and == happens to work
3. min stack that pushes onto the min stack only on a strictly smaller value
push 3, push 3, pop, getMin(): strict -> NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Deque.peek()" is null
correct -> 3 (the stack still holds one 3)
4. encoded min stack with int differences instead of long
push Integer.MIN_VALUE, push Integer.MAX_VALUE, top(): int diffs = -2147483648 long diffs = 2147483647
MAX_VALUE - MIN_VALUE does not fit in an int, wraps to -1, and -1 looks like "new minimum"
5. next greater element popping on <= instead of <
input [2, 2, 3]: buggy = [2, 3, -1] correct = [3, 3, -1]
the first 2 is told its next greater element is 2
6. largest rectangle without the final height-0 bar
input [2, 4]: buggy = 0 correct = 4
nothing ever pops the bars that are still on the stack when the loop ends
7. queue from two stacks that pours on every dequeue
enqueue 1, 2; dequeue; enqueue 3; dequeue: first = 1 (ok), second: broken = 3 correct = 2
the 3 was poured on top of the 2 that was still waiting in the output stack
8. popping an empty structure: both conversions throw NoSuchElementException, as ArrayDeque.pop does