Given a string path, which is an absolute path (starting with a slash '/') to a file or directory in a Unix-style file system, convert it to the simplified canonical path.

In a Unix-style file system, a period '.' refers to the current directory, a double period '..' refers to the directory up a level, and any multiple consecutive slashes (i.e. '//') are treated as a single slash '/'. For this problem, any other format of periods such as '...' are treated as file/directory names.

The canonical path should have the following format:

Return the simplified canonical path.

Input: path = "/home/"
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.
Input: path = "/../"
Output: "/"
Explanation: Going one level up from the root directory is a no-op, as the root level is the highest level you can go.
Input: path = "/home//foo/"
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one.
Constraints:

Contents

In this approach, we will read character by character and construct the path element, when we see '/' apply the rules such as if the current path element is .. then remove the path element before that, and if the path path element is . just skip it (since it is pointing to current directory). We will use a Stack datastructure to store the path elements, so that it makes it easy to apply these path rules, for example if the path is something like this /abc/def/ghi/../../.. simplified path will become / (root directory).

Implementation steps: import java.util.Stack; public class SimplifyPath { static String simplifyPath(String path) { Stack<String> stack = new Stack<>(); String current = ""; for(int i=0; i<=path.length(); i++) { // i<=path.length(), to handle what 'current' holds at the end loop if(i == path.length() || path.charAt(i) == '/') { //directory separator or end of path if("..".equals(current)) { if(!stack.isEmpty()) stack.pop(); // is stack is not empty remove it , otherwise ignore it } else if (!current.isEmpty() && !".".equals(current)) { stack.push(current); } current = ""; } else { current += path.charAt(i); } } return "/" + String.join("/", stack); } public static void main(String[] args) { System.out.println(simplifyPath("/../abc//./def")); System.out.println(simplifyPath("/abc/def/ghi/../../..")); } }
Complexity Analysis:

Time complexity: All the above operations runs in O(n) where n is the length of input string path.
Space complexity: O(n) for storing elements into stack.

In this approach, we will same approach as above, but instead of iterating through each character, we will use utility method String.split(regex) method using regular expression. '/'. (String's split() operation)

import java.util.Stack; public class SimplifyPath { static String simplyPathUsingStringSplit(String path) { Stack<String> stack = new Stack<>(); String[] tokens = path.split("/"); for(String token: tokens) { if("..".equals(token)) { if(!stack.isEmpty()) stack.pop(); } else if (!token.isEmpty() && !".".equals(token) && !"/".equals(token)) { stack.push(token); } } return "/"+String.join("/", stack); } public static void main(String[] args) { System.out.println(simplyPathUsingStringSplit("/../abc//./def")); System.out.println(simplyPathUsingStringSplit("/abc/def/ghi/../../..")); } }
Complexity Analysis:

Time complexity: All the above operations runs in O(n) where n is the length of input string path.
Space complexity: O(n) for storing elements into stack.

Above implementations source code can be found at GitHub link for Java code