Simplify Path
Given a string path'/'
In a Unix-style file system, a period '.''..''//''/''...'
The canonical path should have the following format:
-
The path starts with a single slash
.'/' -
Any two directories are separated by a single slash
.'/' - The path does not end with a trailing '/'.
-
The path only contains the directories on the path from the root directory to the target file or directory (i.e., no period
or double period'.' )'..'
Return the simplified canonical path.
Example 1
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.
Example 2
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.
Example 3
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one.
Constraints:
1 <= path.length <= 3000 consists of English letters, digits, periodpath , slash'.' or'/' .'_' is a valid absolute Unix pathpath
Contents
Solution 1 - Using a stack and read character by character from path
In this approach, we will read character by character and construct the path element, when we see '/'...Stack/abc/def/ghi/../../../
-
First, declare two variables
, astack that we will use to store path elements, andStack acurrent to store current path element.Sting -
Next, loop through each character of
string and if current character ispath or if we reach of end of/ do the following :path-
If the
value iscurrent , and if the.. is not empty, then remove the top the element ofstack and continue.stack -
If the
value is not empty, and if it is NOT equal tocurrent , then add the. path element intocurrent .stack -
Reset the
topath to empty, once we either do one of the above two steps.""
-
If the
-
If the current character is not
, then append the character to/ string.current -
At the end, loop through
elements, and create a new String withstack separator.'/'
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 npath
Space complexity: O(n) for storing elements into stack.
Solution 2 - Using a stack and split the path string by '/'
In this approach, we will same approach as above, but instead of iterating through each character, we will use utility method String.split(regex)'/'
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 npath
Space complexity: O(n) for storing elements into stack.
Above implementations source code can be found at