题目描述
以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。
请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。
示例:
输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
输入:"/a/./b/../../c/"
输出:"/c"
输入:"/a//b////c/d//././/.."
输出:"/a/b/c"
题目链接: https://leetcode-cn.com/problems/simplify-path/
思路1
第一想法是用栈来做,假设每个目录都以/
分隔,首先根据/
分割字符串,可以得到一系列目录,遍历目录,如果当前目录为.
,则不做操作;如果当前目录为..
并且栈不空,则将栈顶元素弹出;否则就将当前目录入栈。然后将栈中的元素弹出,以/
分隔作为答案。但使用栈有一个问题,举个例子,假设输入为/a/b/c
,则栈的情况为栈底|a|b|c|栈顶
,所以c
先弹出,a
最后弹出,最终的结果是/c/b/a
,这是不对的,原因是在输出时我们应该从栈底开始出栈,这种情况下可以使用双端队列 deque 来实现。
代码如下:
class Solution {
public:
string simplifyPath(string path) {
if(path.empty()) return path;
if(path.size()==1) return "/";
if(path.back()=='/') path.pop_back();
deque<string> st; // 使用双端队列而不是栈
int i = 1;
int j = 1;
while(j<path.size()){ // 使用两个指针来分割字符串
if(path[j]!='/') j++;
else{
string ss = path.substr(i, j-i); // ss表示当前目录
if(ss==".."){ // ".."表示出队列
if(!st.empty()) st.pop_back();
}
else if(!ss.empty()){ // 如果ss非空
if(ss.size()>1) st.push_back(ss); //长度大于1说明不是'.',入队列
else if(ss[0]!='.') st.push_back(ss); //第一个字符串为'.'也可以入队列,例如".ssh"
}
while(j<path.size() && path[j]=='/') j++; // 跳过多个'/'的情况,例如"/a/////b/c"
i = j;
}
}
string ss = path.substr(i, j-i); /*提取最后一个目录,入队列的逻辑和上面是一样的*/
if(ss==".."){
if(!st.empty()) st.pop_back();
}
else if(!ss.empty()){
if(ss.size()>1) st.push_back(ss);
else if(ss[0]!='.') st.push_back(ss);
}
if(st.empty()) return "/"; // 别忘了这一句
string ans = "";
while(!st.empty()){
string s = st.front(); st.pop_front(); // 从队头出队列
ans += "/" + s;
}
return ans;
}
};
- 时间复杂度:O(n)
n 为 path 的长度。 - 空间复制度:O(n)
思路2
思路 1 使用双指针来对输入的路径进行分割,可以直接使用 c++ 自带的 istringstream
和 getline
组合来分割字符串,具体代码如下:
class Solution {
public:
string simplifyPath(string path) {
if(path.empty()) return path;
if(path.size()==1) return "/";
deque<string> q;
istringstream iss(path);
string dir = "";
while(getline(iss, dir, '/')){
if(!dir.empty() && dir!="." && dir!=".."){
q.push_back(dir);
}else if(!q.empty() && dir==".."){
q.pop_back();
}
}
if(q.empty()) return "/";
string ans = "";
while(!q.empty()){
string s = q.front(); q.pop_front();
ans += "/" + s;
}
return ans;
}
};
这样代码更加简洁。
参考
思路 2 参考了 https://leetcode-cn.com/problems/simplify-path/comments/69661 。