一、题目描述
给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为 更加简洁的规范路径。
在 Unix 风格的文件系统中规则如下:
- 一个点
'.'表示当前目录本身。 - 此外,两个点
'..'表示将目录切换到上一级(指向父目录)。 - 任意多个连续的斜杠(即,
'//'或'///')都被视为单个斜杠'/'。 - 任何其他格式的点(例如,
'...'或'....')均被视为有效的文件/目录名称。
返回的 简化路径 必须遵循下述格式:
- 始终以斜杠
'/'开头。 - 两个目录名之间必须只有一个斜杠
'/'。 - 最后一个目录名(如果存在)不能 以
'/'结尾。 - 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含
'.'或'..')。
返回简化后得到的 规范路径 。
示例 1:
输入: path = "/home/"
输出: "/home"
解释:
应删除尾随斜杠。
示例 2:
输入: path = "/home//foo/"
输出: "/home/foo"
解释:
多个连续的斜杠被单个斜杠替换。
示例 3:
输入: path = "/home/user/Documents/../Pictures"
输出: "/home/user/Pictures"
解释:
两个点 ".." 表示上一级目录(父目录)。
示例 4:
输入: path = "/../"
输出: "/"
解释:
不可能从根目录上升一级目录。
示例 5:
输入: path = "/.../a/../b/c/../d/./"
输出: "/.../b/d"
解释:
"..." 在这个问题中是一个合法的目录名。
提示:
1 <= path.length <= 3000path由英文字母,数字,'.','/'或'_'组成。path是一个有效的 Unix 风格绝对路径。
二、解答
题目分析
-
任务:
给定一个表示 Unix 风格绝对路径的字符串path,需要将其转换为更加简洁的规范路径。 -
输入:
输入是一个字符串path,它表示一个以'/'开头的 Unix 风格绝对路径。路径中可能包含点(.或..或其他格式的点)、斜杠(可能有多个连续斜杠)以及目录名。 -
输出:
输出是一个符合特定格式的字符串,即规范路径。规范路径的格式要求如下:- 始终以斜杠
'/'开头。 - 两个目录名之间必须只有一个斜杠
'/'。 - 最后一个目录名(如果存在)不能 以
'/'结尾。 - 路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含
'.'或'..')。
- 始终以斜杠
-
关键规则:
- 一个点
'.'表示当前目录本身,在规范路径中应被忽略。 - 两个点
'..'表示将目录切换到上一级(指向父目录),在处理路径时需要相应地向上移动目录层级。 - 任意多个连续的斜杠(即,
'//'或'///')都被视为单个斜杠'/',需要进行合并处理。 - 任何其他格式的点(例如,
'...'或'....')均被视为有效的文件 / 目录名称,应保留在路径中。
- 一个点
示例分析
-
示例 1:
- 输入:
path = "/home/" - 输出:
"/home" - 解释:输入路径末尾有一个斜杠,根据规范路径的要求,最后一个目录名不能以
'/'结尾,所以应删除尾随斜杠。
- 输入:
-
示例 2:
- 输入:
path = "/home//foo/" - 输出:
"/home/foo" - 解释:输入路径中存在多个连续的斜杠,根据规则,任意多个连续的斜杠都被视为单个斜杠,所以将
//替换为/,并且删除末尾的斜杠,得到规范路径"/home/foo"。
- 输入:
-
示例 3:
- 输入:
path = "/home/user/Documents/../Pictures" - 输出:
"/home/user/Pictures" - 解释:路径中遇到
../,表示要切换到上一级目录。/home/user/Documents/../中../使得路径从Documents目录回到user目录,然后再连接Pictures目录,最终得到规范路径"/home/user/Pictures"。
- 输入:
-
示例 4:
- 输入:
path = "/../" - 输出:
"/" - 解释:由于已经在根目录,遇到
../表示尝试从根目录上升一级目录,这是不可能的,所以最终路径仍然是根目录,即"/"。
- 输入:
-
示例 5:
-
输入:
path = "/.../a/../b/c/../d/./" -
输出:
"/.../b/d" -
解释:
"/.../a/../"中a/../使得路径从a目录回到...目录。- 然后连接
b目录,接着c/../使得路径从c目录回到b目录。 - 遇到
d目录连接上,最后./表示当前目录,应被忽略,并且删除末尾的斜杠,最终得到规范路径"/.../b/d"。
-
代码
class Solution {
public String simplifyPath(String path) {
String[] names = path.split("/");
Deque<String> stack = new ArrayDeque<String>();
for (String name : names) {
if ("..".equals(name)) {
if (!stack.isEmpty()) {
stack.pollLast();
}
} else if (name.length() > 0 && !".".equals(name)) {
stack.offerLast(name);
}
}
StringBuffer ans = new StringBuffer();
if (stack.isEmpty()) {
ans.append('/');
} else {
while (!stack.isEmpty()) {
ans.append('/');
ans.append(stack.pollFirst());
}
}
return ans.toString();
}
}
代码分析
代码结构和具体实现分析
1. 方法签名和参数
java
public String simplifyPath(String path)
public表示该方法是公共的,可以被其他类访问。- 返回类型为
String,即最终简化后的规范路径。 - 参数
path是一个String类型,代表输入的 Unix 风格绝对路径。
2. 分割路径字符串
java
String[] names = path.split("/");
- 使用
split("/")方法将输入的路径字符串path按照斜杠/进行分割,得到一个字符串数组names。这样做可以将路径中的各个部分(目录名、点等)分离出来,方便后续处理。
3. 初始化栈
java
Deque<String> stack = new ArrayDeque<String>();
- 创建一个
Deque(双端队列)对象stack,这里使用ArrayDeque来实现栈的功能。栈在处理路径时非常有用,因为可以方便地模拟目录的层级变化,当遇到..时可以从栈中弹出元素表示回到上一级目录。
4. 遍历分割后的路径部分
java
for (String name : names) {
if ("..".equals(name)) {
if (!stack.isEmpty()) {
stack.pollLast();
}
} else if (name.length() > 0 && !".".equals(name)) {
stack.offerLast(name);
}
}
-
使用增强
for循环遍历names数组中的每个元素name。- 当
name为".."时,表示要切换到上一级目录。如果栈不为空,则使用stack.pollLast()方法从栈中弹出栈顶元素,模拟回到上一级目录的操作。 - 当
name的长度大于 0 且不等于"."时,说明这是一个有效的目录名,将其使用stack.offerLast(name)方法添加到栈的末尾。
- 当
5. 构建最终的规范路径
java
StringBuffer ans = new StringBuffer();
if (stack.isEmpty()) {
ans.append('/');
} else {
while (!stack.isEmpty()) {
ans.append('/');
ans.append(stack.pollFirst());
}
}
-
创建一个
StringBuffer对象ans,用于构建最终的规范路径。StringBuffer是可变的,适合在循环中动态添加字符。- 如果栈为空,说明路径经过简化后为空,此时只需要在
ans中添加一个斜杠/,表示根目录。 - 如果栈不为空,使用
while循环从栈的头部依次取出元素,每次取出一个元素前先添加一个斜杠/,然后添加元素本身,直到栈为空。
- 如果栈为空,说明路径经过简化后为空,此时只需要在
6. 返回最终结果
java
return ans.toString();
- 将
StringBuffer对象ans转换为String类型并返回,这就是最终的简化后的规范路径。
总结
这段代码定义了一个名为 Solution 的类,其中包含一个方法 simplifyPath,该方法的作用是将输入的 Unix 风格绝对路径字符串 path 转换为更加简洁的规范路径。