Path Resolution with Symbolic Links
Company: Anthropic
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates a candidate's ability to implement filesystem-style path resolution, including handling relative and absolute paths, dot components, and symbolic link indirection. It tests string parsing, iterative state tracking, and cycle detection logic, commonly used in coding interviews to assess correctness on edge cases and simulation-style problems.
Constraints
- All paths use '/' as the separator and contain no empty components other than those implied by a leading '/'.
- 1 <= number of links <= 10^4; total input size fits comfortably in memory.
- Every '..' is valid to apply (never escapes above '/').
- cwd is absolute and already canonical; link_path values are absolute and canonical.
- A link's target may be absolute or relative and may itself contain '.' and '..'.
Examples
Input: ('/home/user', '../user/docs/./projects', [])
Expected Output: '/home/user/docs/projects'
Explanation: No links. Starting from /home/user: '..' -> /home, 'user' -> /home/user, 'docs' -> /home/user/docs, '.' ignored, 'projects' -> /home/user/docs/projects.
Input: ('/', '/var/log/today/error', [['/var/log/today', '/var/log/2026-06-30']])
Expected Output: '/var/log/2026-06-30/error'
Explanation: Absolute path. After appending 'today' the accumulated path /var/log/today matches a link, so it is replaced by its absolute target /var/log/2026-06-30; the remaining component 'error' is appended to give /var/log/2026-06-30/error.
Input: ('/', '/a/b', [['/a', '/a/b/c'], ['/a/b/c', '/a']])
Expected Output: 'CYCLE'
Explanation: Appending 'a' matches link /a -> /a/b/c; resolving that re-appends 'a', which matches /a again (already followed) -> CYCLE.
Input: ('/home/user', '/', [])
Expected Output: '/'
Explanation: Absolute path with no components resolves to the root.
Input: ('/', '/x/y', [['/x/y', '../z']])
Expected Output: '/z'
Explanation: /x/y is a symlink to the relative target ../z, resolved against its containing directory /x, giving /z.
Input: ('/', '../../..', [])
Expected Output: '/'
Explanation: '..' at the root stays at the root, so repeated '..' clamps to /.
Input: ('/', '/a', [['/a', '/b'], ['/b', '/c/d']])
Expected Output: '/c/d'
Explanation: Chained links: /a -> /b, then /b -> /c/d; each is followed once, ending at /c/d.
Input: ('/home', 'docs', [['/home/docs', '/mnt/docs']])
Expected Output: '/mnt/docs'
Explanation: Relative path 'docs' from /home hits link /home/docs -> absolute target /mnt/docs.
Input: ('/', '/self', [['/self', '/self']])
Expected Output: 'CYCLE'
Explanation: A self-referential link: following /self resolves to /self again, which is already in the visited set -> CYCLE.
Hints
- Model the current location as a stack of path components; the root '/' is the empty stack, and the accumulated absolute path is '/' + '/'.join(stack).
- Keep the yet-to-process components in a queue. When you follow a link, resolve its target into components and push them to the FRONT of the queue so any remaining original components are processed afterward.
- Only check for a link match right after appending a *normal* component (not after '.' or '..'). Relative targets resolve against the link's containing directory, so pop the link's own name off the stack before applying the target; for an absolute target, reset the stack to the root first.
- For cycle detection, record every link_path you follow in a visited set for this single call; if you are about to follow a link_path already in the set, return "CYCLE".