Design a Workspace Resource Manager
Company: Goldman Sachs
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question tests a candidate's ability to design and implement a tree-structured data model with efficient CRUD operations in memory. It evaluates practical object-oriented design, recursive traversal, cycle detection, and algorithmic efficiency under scale constraints — core competencies assessed in software engineering coding interviews.
Constraints
- Up to 10^5 resources and up to 10^5 total operations.
- Ids are unique strings for the lifetime of the workspace and are never reused after a delete.
- Resource names are not unique; the id is the only unique key.
- A folder may not be moved into itself or any of its descendants.
- In the harness, resources are referenced by the integer index of the create op that produced them; a ref of None means the home level.
Examples
Input: ([['create', 'Docs', 'folder', None], ['create', 'notes.txt', 'file', 0], ['create', 'Drafts', 'folder', 0], ['create', 'draft.txt', 'file', 2], ['list', None], ['list', 0], ['move', 1, None], ['list', None], ['list', 0], ['delete', 0], ['list', None]],)
Expected Output: [0, 1, 2, 3, [0], [1, 2], None, [0, 1], [2], None, [1]]
Explanation: The worked example from the prompt: build Docs/notes.txt/Drafts/draft.txt, list home then Docs, move notes.txt to home (home becomes [Docs, notes], Docs becomes [Drafts]), then delete Docs (and Drafts + draft.txt recursively), leaving home = [notes].
Input: ([['list', None]],)
Expected Output: [[]]
Explanation: Edge case: listing the home level of a brand-new workspace returns an empty list.
Input: ([['create', 'a', 'file', None], ['create_err', 'b', 'file', 0], ['create', 'F', 'folder', None], ['create', 'c', 'file', 1]],)
Expected Output: [0, 'ValueError', 1, 2]
Explanation: Creating 'b' inside resource 0 ('a', a file) raises ValueError because you can only create inside a folder; creating 'c' inside resource 1 ('F', a folder) succeeds and gets index 2.
Input: ([['create', 'A', 'folder', None], ['create', 'B', 'folder', 0], ['create', 'C', 'folder', 1], ['move_err', 0, 2], ['move_err', 0, 0], ['move', 1, None], ['list', None], ['list', 0]],)
Expected Output: [0, 1, 2, 'ValueError', 'ValueError', None, [0, 1], []]
Explanation: Chain A>B>C. Moving A into C (its own descendant) and moving A into itself both raise ValueError. Moving B to home succeeds, so home = [A, B] and A now has no direct children (C went with B).
Input: ([['create', 'root', 'folder', None], ['create', 'f1', 'file', 0], ['create', 'f2', 'file', 0], ['create', 'f3', 'file', 0], ['move', 2, None], ['list', 0], ['list', None]],)
Expected Output: [0, 1, 2, 3, None, [1, 3], [0, 2]]
Explanation: Removing a middle child (f2) from a folder preserves the creation order of the remaining children: root keeps [f1, f3]; home gains f2 after root.
Input: ([['create', 'X', 'folder', None], ['create', 'Y', 'folder', 0], ['create', 'leaf', 'file', 1], ['delete', 1], ['list', 0], ['list', None]],)
Expected Output: [0, 1, 2, None, [], [0]]
Explanation: Recursive delete: deleting folder Y also removes its child 'leaf', so X has no children and home still has only X.
Hints
- Store one record per resource in a dict keyed by id, holding its name, type, parent pointer, and an ordered list of child ids. Appending to a per-folder list naturally preserves creation order for list_resources.
- For delete, detach the node from its parent's child list, then iterate its subtree with an explicit stack/queue, removing each id from the dict so deleted ids vanish from every future listing.
- For move, detect cycles by walking from the destination up through parent pointers: if you reach the resource being moved, the destination is inside it, so reject the move.