Skip to content

Simplify Path

Given an absolute file path in a Unix-style file system, return its simplified canonical form.

In a Unix-style file system:

  • A single dot . means “stay in the current directory”
  • A double dot .. means “go up one level” (to the parent directory)
  • Multiple consecutive slashes / are treated as a single slash
  • Any trailing slashes are ignored
InputOutputExplanation
/a/./b/../../c//cStart at a, stay at a (.), go back to root (..), then descend to c
/a/../../b/../c//.///cGo up twice from a (to root and beyond, but capped), descend to b, go up, descend to c
/a//b////c/d//././/../a/b/cMultiple slashes treated as one, dots ignored, go up from d to c
//Root directory stays root
/..//Cannot go above root, so result is /
/a//aTrailing slash is removed
  • 1 <= path.length <= 3000
  • path consists of English letters, digits, ., and /
  • path is a valid absolute Unix path.
ApproachTimeSpaceProsCons
Stack with SplitO(n)O(n)Clean, easy to understand, idiomaticAllocates intermediate array
String ParsingO(n)O(n)Single pass, no intermediate splitMore pointer arithmetic, harder to follow

Both approaches are O(n) time and space. Choose Stack for clarity and interview friendliness, or Parsing if you want to demonstrate low-level string handling.

  • Pick Stack with Split if you want code that is easy to explain and remember.
  • Pick String Parsing if you want to show deep understanding of pointer/index manipulation.
  • In practice, most developers use Stack — it is the most readable.
Recommended
Stack with Split
O(n) time · O(n) space
Low-Level Control
String Parsing
O(n) time · O(n) space
Section titled “Approach 1: Stack with Split (Recommended)”
★ Recommended

Split the path by /, filter out empty strings and . (current directory), use a stack to represent the directory hierarchy. When you encounter .., pop from the stack (go up). When you encounter a directory name, push it (go down). Finally, reconstruct the path from the stack.

The key insight is that the stack is a perfect data structure for a directory path: each element is a directory level, and .. is a pop operation.

⏱ Time O(n) Single pass after split 💾 Space O(n) Stack + split array

Input: /a/./b/../../c/

After split by / and filter: ["a", "b", "c"]

StepComponentActionStack State
1aPush (descend to a)["a"]
2.Skip (stay in current directory)["a"]
3bPush (descend to b)["a", "b"]
4..Pop (go up to a)["a"]
5..Pop (go up to root)[]
6cPush (descend to c)["c"]
FinalJoin with / and prepend //c

Animated walkthrough

How the stack solution builds the canonical path

Watch how each directory component is pushed onto the stack, and how .. pops it off. Empty slashes and dots are ignored.

Step 1 of 8 Target: path
Waiting to begin...
Array state
Memory / lookup state

function simplifyPath(path):
components = split path by '/' and filter empty + '.'
stack = []
for component in components:
if component == "..":
if stack is not empty:
stack.pop()
else:
stack.push(component)
return "/" + join(stack, "/")
simplify_path_stack.py
from typing import List
def simplify_path_stack(path: str) -> str:
"""
Simplify an absolute path using a stack approach.
Time: O(n) where n is the length of the path
Space: O(n) for the stack storing directory names
"""
# Split path by '/' and filter empty strings
parts = [part for part in path.split('/') if part and part != '.']
stack = []
for part in parts:
if part == '..':
# Go up one directory if possible
if stack:
stack.pop()
else:
# Add directory name to stack
stack.append(part)
# Reconstruct the path
return '/' + '/'.join(stack)
if __name__ == "__main__":
# Test cases
print(simplify_path_stack("/a/./b/../../c/")) # "/c"
print(simplify_path_stack("/a/../../b/../c//.//")) # "/c"
print(simplify_path_stack("/a//b////c/d//././/..")) # "/a/b/c"
print(simplify_path_stack("/")) # "/"
print(simplify_path_stack("/../")) # "/"
🎯 Interview Favourite

Instead of splitting the entire path first, parse it character by character. Extract each component between slashes, then apply the same logic: push directory names onto a string buffer, and handle .. by backing up within the buffer.

This approach uses manual index manipulation and is more efficient in languages with mutable strings.

⏱ Time O(n) Single pass, no split 💾 Space O(n) Result string buffer

Input: /a/../../b/../c//.//

StepIndexComponentActionCanonical
Start0(none)Initialize/
11aAppend a/a
23..Backtrack to //
36..Backtrack, but capped at root/
49bAppend b/b
511..Backtrack to //
614cAppend c/c
715+(none)End of string/c
function simplifyPathParsing(path):
canonical = "/"
i = 0
while i < len(path):
skip all '/'
if i >= len(path): break
j = i
extract component from i to next '/'
if component == "..":
remove last component from canonical (backtrack)
else if component != ".":
append component to canonical
i = j
return canonical
simplify_path_parsing.py
from typing import List
def simplify_path_parsing(path: str) -> str:
"""
Simplify an absolute path using string parsing.
Time: O(n) where n is the length of the path
Space: O(n) for the result string
"""
# Start with root
canonical = "/"
i = 0
while i < len(path):
# Skip slashes
while i < len(path) and path[i] == '/':
i += 1
if i >= len(path):
break
# Extract the next component
j = i
while j < len(path) and path[j] != '/':
j += 1
component = path[i:j]
if component == '..':
# Go up one level (remove last component from canonical)
# Find the last '/' and remove everything after it
last_slash = canonical.rfind('/')
if last_slash > 0: # Don't go above root
canonical = canonical[:last_slash]
elif component != '.':
# Add the component to canonical path
if canonical != '/':
canonical += '/'
canonical += component
# If component == '.', we skip it (stay in current directory)
i = j
return canonical
if __name__ == "__main__":
# Test cases
print(simplify_path_parsing("/a/./b/../../c/")) # "/c"
print(simplify_path_parsing("/a/../../b/../c//.//")) # "/c"
print(simplify_path_parsing("/a//b////c/d//././/..")) # "/a/b/c"
print(simplify_path_parsing("/")) # "/"
print(simplify_path_parsing("/../")) # "/"
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
simplify_path_space_optimized.py
"""
Solution for Simplify Path
"""
def solve():
"""Implementation for approach 3 of Simplify Path"""
pass
if __name__ == "__main__":
print("Solution ready")