Simplify Path
Given an absolute Unix-style file path, return its simplified canonical form.
Open on LeetCode ↗Intuition
The tempting shortcut is to special-case anything that looks like dots, but ... is a perfectly ordinary directory name — only the exact token .. means go up, and treating triple-dot as special silently corrupts otherwise-valid paths. A path is really a sequence of directory pushes with .. as a pop, which makes a stack the natural model. Split on /, then classify each piece: empty or . is ignored, .. pops if anything is there, and anything else — however odd it looks — is pushed. Rejoin with / and prefix a slash.
Split on / and let a stack model the directory hierarchy: a name pushes, .. pops, and . or an empty segment is noise. The stack is the resulting path, so joining it produces the canonical form directly.
Approach
Split and let empties fall out
path.split('/') on "/a//b" yields empty strings where consecutive or trailing slashes occurred. Rather than pre-cleaning the input, simply skip empty pieces during the scan — that handles every multiple-slash case at once.
Classify each component
"" and "." mean stay put, so skip them. ".." means go up, so pop the stack — but only if it is non-empty, since the root has no parent and /.. must stay /. Anything else is a directory name and gets pushed, including odd-looking ones like "...", which is a legal name and not a special token.
Rejoin
Return '/' + '/'.join(stack). An empty stack yields exactly "/", which is the correct canonical root, so no separate case is needed. The output has no trailing slash and no repeated separators. O(n) time and O(n) space.
Solution & live demo
Common pitfalls
Popping an empty stack
if part == '..':
st.pop()if part == '..':
if st:
st.pop().. at the root has nowhere to go — /../ is just /. Popping unguarded throws on any path that tries to ascend past the root.
Not filtering empty segments
for part in path.split('/'):
st.append(part)if part == '' or part == '.':
continueConsecutive slashes and the leading slash produce empty strings from the split. Pushing them creates phantom directories and doubled separators in the output.
Joining without the leading slash
return '/'.join(st)
return '/' + '/'.join(st)
The canonical path is absolute and must begin at the root. Without the prefix an empty stack returns "" rather than "/", and every other path loses its leading separator.
Edge cases
The stack is empty so the pop is skipped and the result is "/".
Empty pieces are skipped, giving "/home/foo".
Two pops unwind a and b, leaving "/c".
Three dots is an ordinary directory name, not an up-level token — it is pushed.