Normalize pathnames
Give a path name (absolute or relative) normalize it and return the shortest path representing the given path.
Example
normalize('/abc/def/../') #=> 'abc/'
normalize('/abc/def/../../') #=> ''
normalize('abc/def/../../../') #=> '../'
normalize('/abc/def/../../../') #=> Invalid path name
Solution
- Use a stack to keep track of the path name
- Split the pathname by '/'
- Push into the stack when we see anything other than '.' and '..'
- For '..' pop from stack
- When starting with '/' handle empty array appropriately when pop fails
- When not starting with '/' keep track of '../' seen so we can still report the shortest path
Code
def normalize(pathname)
return nil if pathname.nil?
stack = []
i = 0
starts_at_root = false
# If it starts with '/' insert that into stack
if pathname[0] == '/'
stack.push('/')
starts_at_root = true
i += 1
end
# Split and analyze the pathname
pathname_arr = pathname.split('/')
while i < pathname_arr.size
c = pathname_arr[i]
if c == '.' || c == ''
# Do nothing
elsif c == ".."
if starts_at_root && stack.empty?
raise StandardError.new('Invalid path provided')
elsif stack.empty? || stack.last == '..'
stack.push('..')
else
stack.pop
end
else
stack.push(c)
end
i += 1
end
## Construct pathname in reverse order
normalized_pathname = ''
while !stack.empty?
normalized_pathname = "#{stack.pop}/#{normalized_pathname}"
end
normalized_pathname
end
Time complexity
- O(n) time where n is the length of the path