力扣题目-简化路径

83 阅读6分钟

一、题目描述

给你一个字符串 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 <= 3000
  • path 由英文字母,数字,'.''/' 或 '_' 组成。
  • path 是一个有效的 Unix 风格绝对路径。

二、解答

题目分析

  1. 任务
    给定一个表示 Unix 风格绝对路径的字符串 path,需要将其转换为更加简洁的规范路径。

  2. 输入
    输入是一个字符串 path,它表示一个以 '/' 开头的 Unix 风格绝对路径。路径中可能包含点(. 或 .. 或其他格式的点)、斜杠(可能有多个连续斜杠)以及目录名。

  3. 输出
    输出是一个符合特定格式的字符串,即规范路径。规范路径的格式要求如下:

    • 始终以斜杠 '/' 开头。
    • 两个目录名之间必须只有一个斜杠 '/' 。
    • 最后一个目录名(如果存在)不能 以 '/' 结尾。
    • 路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.' 或 '..')。
  4. 关键规则

    • 一个点 '.' 表示当前目录本身,在规范路径中应被忽略。
    • 两个点 '..' 表示将目录切换到上一级(指向父目录),在处理路径时需要相应地向上移动目录层级。
    • 任意多个连续的斜杠(即,'//' 或 '///')都被视为单个斜杠 '/',需要进行合并处理。
    • 任何其他格式的点(例如,'...' 或 '....')均被视为有效的文件 / 目录名称,应保留在路径中。

示例分析

  1. 示例 1

    • 输入path = "/home/"
    • 输出"/home"
    • 解释:输入路径末尾有一个斜杠,根据规范路径的要求,最后一个目录名不能以 '/' 结尾,所以应删除尾随斜杠。
  2. 示例 2

    • 输入path = "/home//foo/"
    • 输出"/home/foo"
    • 解释:输入路径中存在多个连续的斜杠,根据规则,任意多个连续的斜杠都被视为单个斜杠,所以将 // 替换为 /,并且删除末尾的斜杠,得到规范路径 "/home/foo"
  3. 示例 3

    • 输入path = "/home/user/Documents/../Pictures"
    • 输出"/home/user/Pictures"
    • 解释:路径中遇到 ../,表示要切换到上一级目录。/home/user/Documents/../ 中 ../ 使得路径从 Documents 目录回到 user 目录,然后再连接 Pictures 目录,最终得到规范路径 "/home/user/Pictures"
  4. 示例 4

    • 输入path = "/../"
    • 输出"/"
    • 解释:由于已经在根目录,遇到 ../ 表示尝试从根目录上升一级目录,这是不可能的,所以最终路径仍然是根目录,即 "/"
  5. 示例 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 转换为更加简洁的规范路径。