71. Simplify Path


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:

  • 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:

Input: path = "/home/"
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.

Example 2:

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.

Example 3:

Input: path = "/home//foo/"
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one. 

Constraints:

  • 1 <= path.length <= 3000
  • path consists of English letters, digits, period '.', slash '/' or '_'.
  • path is a valid absolute Unix path.

这道题让简化给定的路径,光根据题目中给的那一个例子还真不太好总结出规律,应该再加上两个例子 path = "/a/./b/../c/" => "/a/c" 和 path = "/a/./b/c/" => "/a/b/c",这样就可以知道中间是 “.” 的情况直接去掉,而是 “..” 时删掉它上面挨着的一个路径,而下面的边界条件给的一些情况中可以得知,如果是空的话返回 “/“,如果有多个 “/“ 只保留一个。那么可以把路径看做是由一个或多个 “/“ 分割开的众多子字符串,把它们分别提取出来一一处理即可,代码如下:

C++ 解法一:

class Solution {
public:
    string simplifyPath(string path) {
        string res;
        vector<string> dirs;
        int i = 0, n = path.size();
        while (i < n) {
            while (path[i] == '/' && i < n) ++i;
            if (i == path.size()) break;
            int start = i;
            while (path[i] != '/' && i < n) ++i;
            int end = i - 1;
            string s = path.substr(start, end - start + 1);
            if (s == "..") {
                if (!dirs.empty()) dirs.pop_back(); 
            } else if (s != ".") {
                dirs.push_back(s);
            }
        }
        for (string str : dirs) res += "/" + str;
        return res.empty() ? "/" : res;
    }
};

还有一种解法是利用了C语言中的函数 strtok 来分隔字符串,但是需要把 string 和 char* 类型相互转换,转换方法请猛戳这里。除了这块不同,其余的思想和上面那种解法相同,代码如下:

C 解法一:

class Solution {
public:
    string simplifyPath(string path) {
        vector<string> v;
        char *cstr = new char[path.length() + 1];
        strcpy(cstr, path.c_str());
        char *pch = strtok(cstr, "/");
        while (pch != NULL) {
            string p = string(pch);
            if (p == "..") {
                if (!v.empty()) v.pop_back();
            } else if (p != ".") {
                v.push_back(p);
            }
            pch = strtok(NULL, "/");
        }
        if (v.empty()) return "/";
        string res;
        for (int i = 0; i < v.size(); ++i) {
            res += '/' + v[i];
        }
        return res;
    }
};

C++ 中也有专门处理字符串的机制,我们可以使用 stringstream 来分隔字符串,然后对每一段分别处理,思路和上面的方法相似,参见代码如下:

C++ 解法二:

class Solution {
public:
    string simplifyPath(string path) {
        string res, t;
        stringstream ss(path);
        vector<string> dirs;
        while (getline(ss, t, '/')) {
            if (t == "" || t == ".") continue;
            if (t == ".." && !dirs.empty()) dirs.pop_back();
            else if (t != "..") dirs.push_back(t);
        }
        for (string str : dirs) res += "/" + str;
        return res.empty() ? "/" : res;
    }
};

Java 解法二:

public class Solution {
    public String simplifyPath(String path) {
        Stack<String> s = new Stack<>();
        String[] p = path.split("/");
        for (String t : p) {
            if (!s.isEmpty() && t.equals("..")) {
                s.pop();
            } else if (!t.equals(".") && !t.equals("") && !t.equals("..")) {
                s.push(t);
            }
        }
        List<String> list = new ArrayList(s);
        return "/" + String.join("/", list);
    }
}

Github 同步地址:

https://github.com/grandyang/leetcode/issues/71

参考资料:

https://leetcode.com/problems/simplify-path

https://leetcode.com/problems/simplify-path/solutions/25680/c-10-lines-solution/

https://leetcode.com/problems/simplify-path/solutions/1847357/c-easy-stack-simple-explained-algorithm/

LeetCode All in One 题目讲解汇总(持续更新中…)

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)

知识星球 喜欢请点赞,疼爱请打赏❤️.

微信打赏

|

Venmo 打赏


—|—


转载请注明来源于 Grandyang 的博客 (grandyang.com),欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 grandyang@qq.com

💰


微信打赏


Venmo 打赏

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,试运营期间前五十位可享受半价优惠~)

×

Help us with donation