package com.freetymekiyan.algorithms.level.medium; import org.junit.Assert; import org.junit.Test; import java.util.ArrayDeque; import java.util.Deque; /** * Given an absolute path for a file (Unix-style), simplify it. * <p> * For example, * path = "/home/", => "/home" * path = "/a/./b/../../c/", => "/c" * <p> * Corner Cases: * Did you consider the case where path = "/../"? * In this case, you should return "/". * Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". * In this case, you should ignore redundant slashes and return "/home/foo". * <p> * Company Tags: Microsoft, Facebook * Tags: Stack, String */ public class SimplifyPath { /** * Stack. * Split path with slash, there can be 4 situations: * 1) A correct name, push into stack. * 2) A dot, skip. * 3) Double dot, should pop last directory from stack, if not empty. * 4) Empty, skip. * Finally, go through stack and concatenate words. * Implementation: * Check input path. If it's null or empty, return empty string. * Create a deque as stack. * Split input path with slash. Get a string array of names. * For each name in names: * | If name is empty, OR name is a dot: * | Skip. * | If name is "..": * | Pop from stack. But make sure stack is not empty first. * | Else if it's just a name: * | Push the name onto stack. * Create a string builder for result * While stack is not empty: * | Insert the name popped from stack to the front. * | Insert a slash to the front before the name. * Return "/" if string builder is empty. Otherwise return the string. */ public String simplifyPath(String path) { if (path == null || path.isEmpty()) { return ""; } Deque<String> s = new ArrayDeque<>(); String[] words = path.split("/"); for (String str : words) { if (str.length() == 0 || str.equals(".")) { // Empty or 1 dot, skip. continue; } if (str.equals("..")) { // Double dots, pop. if (!s.isEmpty()) { // Note that we should check whether stack is empty. s.pop(); } } else { // A valid word, push. s.push(str); } } StringBuilder res = new StringBuilder(); while (!s.isEmpty()) { res.insert(0, s.pop()).insert(0, "/"); } return res.length() == 0 ? "/" : res.toString(); } @Test public void testExamples() { Assert.assertEquals("/home", simplifyPath("/home/")); Assert.assertEquals("/c", simplifyPath("/a/./b/../../c/")); Assert.assertEquals("/", simplifyPath("/../")); Assert.assertEquals("/home/foo", simplifyPath("/home//foo/")); Assert .assertEquals("/e/f/g", simplifyPath("/a/./b///../c/../././../d/..//../e/./f/./g/././//.//h///././/..///")); } }