Design file deduplication across nested directories
Company: Anthropic
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's competency in file system traversal, robust I/O handling including symbolic links and cycles, content-based deduplication, and algorithmic efficiency within the Coding & Algorithms domain.
Constraints
- 1 <= len(fs) <= 10^5
- The file system graph may contain cycles due to symbolic links or repeated child references
- File contents are strings
- The total length of all reachable file contents is at most 10^6 characters
- Broken symlinks may appear and should be ignored
Examples
Input: ({'/': {'type': 'dir', 'children': ['/docs', '/img', '/readme.txt']}, '/docs': {'type': 'dir', 'children': ['/docs/a.txt', '/docs/b.txt']}, '/img': {'type': 'dir', 'children': ['/img/pic.bin']}, '/readme.txt': {'type': 'file', 'content': 'hello'}, '/docs/a.txt': {'type': 'file', 'content': 'alpha'}, '/docs/b.txt': {'type': 'file', 'content': 'hello'}, '/img/pic.bin': {'type': 'file', 'content': 'xyz'}}, '/')
Expected Output: [['/docs/b.txt', '/readme.txt']]
Explanation: Only '/docs/b.txt' and '/readme.txt' have identical content.
Input: ({'/': {'type': 'dir', 'children': ['/A', '/B']}, '/A': {'type': 'dir', 'children': ['/A/f1.txt', '/A/to_root']}, '/B': {'type': 'dir', 'children': ['/B/f2.txt', '/B/link_to_A']}, '/A/f1.txt': {'type': 'file', 'content': 'same-data'}, '/B/f2.txt': {'type': 'file', 'content': 'same-data'}, '/A/to_root': {'type': 'symlink', 'target': '/'}, '/B/link_to_A': {'type': 'symlink', 'target': '/A'}}, '/')
Expected Output: [['/A/f1.txt', '/B/f2.txt']]
Explanation: The symlinks create cycles back to already visited directories, but the traversal remains safe. The two real files are duplicates.
Hints
- Treat the structure as a graph, not a tree. Keep visited sets for resolved directories and resolved files so symlink cycles do not cause infinite traversal.
- Do not fully compare every file against every other file. First group by size, then by a cheap prefix/suffix signature, and only then compute a full hash for the remaining candidates.