Nested Todo List
Reported by candidates from Notion's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The Notion OA reported in June 2026 is a design-flavored simulation, and the whole thing hinges on one data structure choice: a hash map of id to node, where each node holds an ordered list of child ids. Nested Todo List sounds like a tree problem, but you're just processing ADD, TOGGLE, GET and RENDER in order. Nothing exotic. The risk is sloppy bookkeeping, not hard algorithms. If you blank on structure, StealthCoder runs invisibly during the live OA and gives you a working solution as a safety net. Know the shape first, though.
The problem
Process operations against an initially empty nested todo list. Items form an ordered forest. ["ADD", id, parentId, text] adds a pending item. A parentId of - makes it a root; otherwise it becomes the newest child of that parent. ["TOGGLE", id] switches that item between PENDING and DONE. Toggling one item does not change descendants or ancestors. ["GET", id] returns id|parentId|status|text. ["RENDER"] returns every item in preorder. Each line is depth|id|status|text, roots and siblings retain insertion order, and lines are joined by a newline. Return the values produced by GET and RENDER operations in order. Function runNestedTodoList(operations: String[][]) → String[] Examples Example 1 operations = [["ADD","1","-","Plan"],["ADD","2","1","Draft"],["ADD","3","1","Review"],["TOGGLE","2"],["GET","2"],["RENDER"]] return = ["2|1|DONE|Draft","0|1|PENDING|Plan\n1|2|DONE|Draft\n1|3|PENDING|Review"] The two children retain insertion order. Toggling item 2 changes only that item. Constraints 1 <= operations.length <= 20000. IDs are unique non-empty strings containing neither | nor whitespace. Every non-root parent exists before its child is added. Every GET and TOGGLE references an existing item. Text is non-empty and contains neither | nor a newline. The total number of rendered item lines is at most 200000.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Keep a map from id to a node with parentId, text, status, and a children array. Keep a separate roots array for items with parentId "-". ADD pushes the id onto its parent's children (or roots), so insertion order is free. TOGGLE flips one status field, with no propagation to ancestors or descendants. GET formats a single string. RENDER is a preorder DFS from each root in order, emitting depth|id|status|text. The pitfall is recursion depth. With up to 20000 operations, a chain of nested items can overflow the stack, so use an explicit stack and push children in reverse. Another trap is joining RENDER lines with a real newline and returning one string per RENDER call. If you freeze mid-OA, StealthCoder is the hedge that gets the structure on screen quickly.
StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.
You can drill Nested Todo List cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. If you're reading this with an OA window open, you're who this was built for.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Notion's OA.
Notion reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Nested Todo List FAQ
What's the trick in the Notion Nested Todo List problem?+
Use a hash map from id to node, plus a children list per node and a roots list. Insertion order comes from appending. RENDER is a preorder traversal. Toggle only touches one node, so there's no cascading logic to build.
How hard is this one really?+
Easy to medium. No clever algorithm is needed. The difficulty is careful implementation: output formatting, ordering, and deep nesting. If you've written a basic tree with child lists before, you can finish this quickly.
Should I use recursion for RENDER?+
Be careful. Up to 20000 operations means a chain of nested items could be thousands deep, which risks stack overflow in some languages. An iterative DFS with an explicit stack is safer. Push children in reverse order so they pop in insertion order.
What output format mistakes cost people points?+
Mixing up the GET format (id|parentId|status|text) with the RENDER format (depth|id|status|text). Also, RENDER returns one string per call with lines joined by a newline, not a list of lines. Root parentId prints as the dash.
How do I prepare for this in 48 hours?+
Write a small tree with a map and child lists, then do an iterative preorder traversal with depth tracking. Test with the sample, then add a deep chain and a multi-root case. Practice reading the spec closely, since formatting is where bugs hide.