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/
LeetCode All in One 题目讲解汇总(持续更新中…)
(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)
微信打赏
|
Venmo 打赏
—|—
转载请注明来源于 Grandyang 的博客 (grandyang.com),欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 grandyang@qq.com