DAY 21 / 30 · WEEK 3 REVIEW

Week 3 Review

Goal of the day

Concept

Week 3 looks like six separate topics, but almost every one of them is answering the same underlying question: what's the cheapest way to add or remove exactly where this problem needs it? A linked list (Day 15/16) buys O(1) insert/delete at a known pointer, when an array's O(n) shift would be too slow — and its fast/slow-pointer trick turns "find the middle" or "detect a cycle" into a single pass with no extra memory. A stack (Day 17) is the natural fit whenever the rule is "deal with the most recently opened thing first" — matching brackets, undo, backtracking. A queue or deque (Day 18) is the mirror image: oldest goes first, or (for a deque) both ends need to move. Trees (Day 19) don't have one traversal order — BFS and DFS are the exact same "explore the frontier" idea, just fed into a queue (level by level) or a stack (full depth before backtracking). A binary search tree (Day 20) is a tree with one extra invariant — everything left of a node is smaller, everything right is bigger, at every level, not just the immediate children — which is what turns search/insert into O(h) and makes an inorder walk come out already sorted.

That last connection is worth sitting with: Day 20 validated a BST by tracking a shrinking min/max bound down each recursive call. There's a completely different way to prove the exact same thing, using this week's other big idea instead of recursion — walk the tree inorder with an explicit stack (Day 17's tool, not the call stack) and confirm every value that comes out is strictly bigger than the last one you saw. If that's ever not true, the tree isn't a valid BST — no bounds tracking required, because a valid BST's inorder sequence is the sorted order, by definition. Today's visualization builds exactly that.

Diagram: which Week 3 structure do I reach for?

Need LIFO — undo, matching, or DFS backtracking? Stack (Day 17) Need FIFO, or a window with two moving ends? Queue / Deque (Day 18) Need O(1) insert/delete at a known node or pointer? Linked List (Day 15/16) Need every node at distance k before any at distance k+1? BFS (Queue) (Day 19) Need to fully explore one path before backtracking? DFS (Stack) (Day 19) Need sorted-order search or insert in O(h) time? BST (Day 20) Check these top to bottom — the first "yes" is usually your pattern. Rows 4-5 assume a tree/graph is already given, not built from scratch.

Interactive visualization: validating a BST with an explicit stack, no bounds tracking

Same 7-node BST as Day 20. Walk it inorder using an explicit stack (Day 17's tool) instead of recursion. Every value popped off the stack must be strictly bigger than the last one popped — that single running check is the whole BST validation, because a valid BST's inorder sequence is always sorted.

pushed, waiting on the stack just popped — comparing to the last value confirmed valid so far broke the invariant — invalid
Press Play or Step to begin.

Dry run: iterative inorder validate, the valid tree (20/30/40/50/60/70/80)

ActionStack (bottom → top)Poppedprev → curr check
Descend left from 5050, 30, 20
Pop50, 3020prev=null → OK, prev=20
No right child; pop503030 > 20 → OK, prev=30
Descend right of 30, then left50, 40
Pop504040 > 30 → OK, prev=40
No right child; pop(empty)5050 > 40 → OK, prev=50
Descend right of 50, then left70, 60
Pop706060 > 50 → OK, prev=60
No right child; pop(empty)7070 > 60 → OK, prev=70
Descend right of 7080
Pop(empty)8080 > 70 → OK, prev=80

Every pop was strictly bigger than the one before it — 20, 30, 40, 50, 60, 70, 80 — so the whole tree is confirmed valid. No min/max bound was ever tracked; the stack's LIFO order plus one running comparison did all the work.

Week 3 cheat sheet — code templates

// LINKED LIST (Day 15/16) — Node + insert at head, O(1)
class Node {
  constructor(val) { this.val = val; this.next = null; }
}
function insertAtHead(head, val) {
  const node = new Node(val);
  node.next = head;
  return node; // new head
}

// FAST/SLOW POINTERS (Day 16) — find the middle in one pass
function middleNode(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }
  return slow; // middle (or 2nd middle on even length)
}

// STACK (Day 17) — plain array, push/pop at the END, O(1) each
const stack = [];
stack.push(x);       // add to top
const top = stack.pop(); // remove from top

// QUEUE / DEQUE (Day 18) — plain array, both ends
const queue = [];
queue.push(x);        // add to back
const front = queue.shift(); // remove from front
queue.unshift(x);     // add to front (deque only)

// BFS (Day 19) — level order, uses a QUEUE
function bfs(root) {
  const order = [];
  const queue = root ? [root] : [];
  while (queue.length > 0) {
    const node = queue.shift();
    order.push(node.val);
    if (node.left) queue.push(node.left);
    if (node.right) queue.push(node.right);
  }
  return order;
}

// DFS (Day 19) — depth order, uses a STACK (explicit, no recursion)
function dfs(root) {
  const order = [];
  const stack = root ? [root] : [];
  while (stack.length > 0) {
    const node = stack.pop();
    order.push(node.val);
    if (node.right) stack.push(node.right); // push right first
    if (node.left) stack.push(node.left);   // so left pops first
  }
  return order;
}

// BST search / insert (Day 20) — O(h)
function search(root, val) {
  let curr = root;
  while (curr) {
    if (val === curr.val) return curr;
    curr = val < curr.val ? curr.left : curr.right;
  }
  return null;
}

// TODAY'S SYNTHESIS — validate a BST via iterative inorder + one stack
function isValidBSTIterative(root) {
  const stack = [];
  let curr = root;
  let prev = null; // no value seen yet
  while (curr || stack.length > 0) {
    while (curr) { stack.push(curr); curr = curr.left; } // descend all the way left
    curr = stack.pop();
    if (prev !== null && curr.val <= prev) return false;  // out of order — invalid
    prev = curr.val;
    curr = curr.right; // then explore the right subtree
  }
  return true;
}

Complexity — everything from Week 3, at a glance

OperationTimeSpaceNote
Linked list insert/delete at a known node (Day 15/16)O(1)O(1)No shifting — only pointers change. Finding that node first is O(n).
Fast/slow middle or cycle detection (Day 16)O(n)O(1)One pass, two pointers — no extra data structure needed.
Stack push/pop/top (Day 17)O(1) eachO(n)Array's built-in push/pop are already O(1) — no shifting at the end.
Queue enqueue/dequeue via array (Day 18)O(1) push, O(n) shiftO(n)push() is O(1); shift() re-indexes every remaining element — a real linked-list-backed queue avoids this.
BFS / DFS traversal (Day 19)O(V + E)O(V)Every node enqueued/pushed and processed exactly once; space is the widest frontier (BFS) or deepest path (DFS).
BST search / insert (Day 20)O(h)O(1) iterativeh = tree height — O(log n) if balanced, degrades to O(n) if skewed (Day 20's sorted-insert trap).
Iterative inorder BST validate (today)O(n)O(h)Every node is pushed and popped exactly once; the stack never holds more than one root-to-leaf path at a time.

Interview corner

How to talk through it out loud: name the access pattern before the structure — "I need the most recently seen item first, so this is a stack problem" or "this needs everything at the current depth processed before going deeper, so BFS with a queue" — the same way Week 2 taught naming the constraint before naming the algorithm. When a problem visibly combines two ideas (a BST validated with a stack, a tree walked with a queue), say so explicitly — interviewers read that as recognizing structure, not stitching code together by trial and error.

5 mixed practice problems

1. Palindrome Linked List (Easy — LeetCode: Palindrome Linked List)

Given the head of a singly linked list, determine if it reads the same forward and backward. Combines Day 15's list walk with Day 16's fast/slow-pointer instinct.

2. Implement Stack using Queues (Easy — LeetCode: Implement Stack using Queues)

Implement a LIFO stack using only queue operations (push to back, pop from front). The mirror image of Day 18's Implement Queue using Stacks.

3. Kth Smallest Element in a BST (Medium — LeetCode: Kth Smallest Element in a BST)

Given a BST, find the kth smallest value. Today's exact iterative-inorder-with-a-stack technique, stopping early instead of walking the whole tree.

4. Binary Tree Zigzag Level Order Traversal (Medium — LeetCode: Binary Tree Zigzag Level Order Traversal)

Return level-order traversal, but alternate direction each level (left→right, then right→left, and so on). Day 19's BFS-with-a-queue, plus one direction flip per level.

5. Lowest Common Ancestor of a Binary Search Tree (Medium — LeetCode: Lowest Common Ancestor of a Binary Search Tree)

Given a BST and two of its nodes, find their lowest common ancestor. The BST invariant (Day 20) turns a generic-tree LCA problem — which needs a stack/recursion to search both subtrees — into a single O(h) walk with no backtracking at all.

Quiz

1. Which Week 3 structure fits "process the most recently seen item first"?

2. What's the one structural change that turns a BFS traversal into a DFS traversal?

3. Why can an iterative inorder walk validate a BST without tracking min/max bounds?

4. How many passes over a linked list does the fast/slow-pointer technique need to find the middle?

5. Why is a plain JavaScript array a poor choice for a queue at scale?