Implement DeleteTree With Limited Filesystem APIs
DatadogSoftware Engineer · Technical ScreenLast updated
Implement a robust recursive tree-deletion algorithm using a restricted set of filesystem primitives. This question tests post-order traversal, managing call-stack and heap memory across deep and wide directory structures, and handling edge cases cleanly.
Problem Statement
You are working with a remote storage client that provides only low-level filesystem operations. You need to implement a function delete_tree(fs: FileSystem, root_path: str) -> None that completely removes the file or directory located at root_path, including all nested files and subdirectories (equivalent to rm -rf).
The target filesystem enforces that a directory cannot be deleted unless it is completely empty.
Provided Interface
You are given an instance of FileSystem with the following methods:
class FileSystem:
def is_directory(self, path: str) -> bool:
"""Returns True if path points to a directory, False if it is a regular file.
Raises an error if path does not exist.
"""
pass
def list_dir(self, path: str) -> list[str]:
"""Returns a list of immediate child names (not full paths) within path.
Raises an error if path is not a directory.
"""
pass
def delete_file(self, path: str) -> None:
"""Deletes a single file. Raises an error if path is a directory or does not exist."""
pass
def delete_directory(self, path: str) -> None:
"""Deletes an empty directory. Raises an error if path is not empty or does not exist."""
pass
Function Signature
def delete_tree(fs: FileSystem, root_path: str) -> None:
pass
Constraints
- The directory tree may contain up to
100,000total items. - Maximum depth of the tree can be up to
20,000. Solutions relying on standard recursive calls will trigger a stack overflow in languages with fixed recursion limits (such as Python). - Paths are separated by
/. Avoid trailing slashes in child paths (e.g., if parent is/a/band child isc, the path is/a/b/c). root_pathmay point directly to a file rather than a directory.
Examples
Example 1:
/app
├── config.json
└── logs/
└── app.log
Input: root_path = "/app"
Execution order:
- Delete
/app/config.json(file) - Delete
/app/logs/app.log(file) - Delete
/app/logs(now empty directory) - Delete
/app(now empty directory)
Example 2:
Input: root_path = "/app/config.json"
Execution order:
- Delete
/app/config.json(single file deletion)
Hints
Hint 1
Because a directory can only be deleted once all of its descendants are deleted, the deletion order must strictly follow a post-order traversal.
Hint 2
A standard recursive DFS will fail with a recursion limit error on deeply nested trees; use an explicit stack to simulate the traversal iteratively.
Hint 3
To achieve post-order traversal with an explicit stack, track whether an entry on the stack is being visited for the first time (to expand children) or the second time (to delete the empty directory).
Follow-up questions
- What changes would be required if `list_dir` returned an iterator/generator instead of a full list, to avoid high memory usage on directories containing millions of files?
- How would you parallelize this operation using a thread pool while ensuring directories are only deleted after all child tasks have completed?
- If an unexpected crash or network partition occurs mid-deletion, how can you ensure the operation is safe to resume and idempotent?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.