一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
题目说明
给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,'//')都被视为单个斜杠 '/' 。 对于此问题,任何其他格式的点(例如,'...')均被视为文件/目录名称。
请注意,返回的 规范路径 必须遵循下述格式:
- 始终以斜杠 '/' 开头。
- 两个目录名之间必须只有一个斜杠 '/' 。
- 最后一个目录名(如果存在)不能 以 '/' 结尾。
- 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.' 或 '..')。
返回简化后得到的 规范路径 。
示例 1:
输入:path = "/home/" 输出:"/home" 解释:注意,最后一个目录名后面没有斜杠
双端队列
基本思路很简单,不难想的到,主要是一下规则:
- “abcd”可以接受
- “//”只要“/”
- “.."意味着删除原先“/abcd/”
从上面三点我们可以看出来,需要用到“后进先出”的概念,我们可能会使用栈。但是还有边界问题:比如删除包含了‘/’的选择处理;空栈怎么办;"..."怎么办,诸如此类。 所以我们不能单个处理字符,那就一次处理多个字符。我们发现栈最后还要倒出来进行反转,那就直接使用双端队列就好了。
class Solution {
public String simplifyPath(String path) {
Deque<String> q = new ArrayDeque<>();
for(String i : path.split("/")){
if(i.equals("..")&&q.peek()!=null) q.removeLast();
else if(!i.equals("..") && !i.equals(".") && !i.equals("")) q.addLast(i);
}
StringBuilder sb = new StringBuilder();
while(q.peek()!=null){
sb.append("/");
sb.append(q.removeFirst());
}
return sb.length() == 0 ?"/":sb.toString();
}
}
字符串模拟
分析
因为String类有个split方法,可以返回一个数组。那么就可以处理下面几种情况
- 当字符串只包含分隔符时,返回数组没有元素;
- 当字符串不包含分隔符时,返回数组只包含一个元素(该字符串本身);
- 字符串最尾部出现的分隔符可以看成不存在,不影响字符串的分隔;
- 字符串最前端出现的分隔符将分隔出一个空字符串以及剩下的部分的正常分隔;
class Solution {
public String simplifyPath(String path) {
String[] splits = path.split("/");
String ans = "";
Stack<String> s = new Stack<>();
for (String sub : splits){
if (sub.length() == 0 || sub.equals(".")){
continue;
}
if (sub.equals("..")){
if(!s.isEmpty()){
s.pop();
}
continue;
}
s.push(sub);
}
while (!s.isEmpty()){
ans = "/" + s.pop() + ans;
}
if (ans.length() == 0) ans += "/";
return ans;
}
}
注意点
如果先以 / 为分割符,将字符串分割成许多个字符串(文件名),遍历这些字符串,如果是正常的文件名就直接入栈,如果是".."弹出栈顶元素,如果是'.'不用管他,到最后再遍历栈,将出栈的元素插入到返回字符串的头上同时加上'/'。