【C/C++】388. 文件的最长绝对路径

227 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情


题目链接:388. 文件的最长绝对路径

题目描述

假设有一个同时存储文件和目录的文件系统。下图展示了文件系统的一个示例:

mdir.jpg

这里将 dir 作为根目录中的唯一目录。dir 包含两个子目录 subdir1subdir2subdir1 包含文件 file1.ext 和子目录 subsubdir1subdir2 包含子目录 subsubdir2,该子目录下包含文件 file2.ext

在文本格式中,如下所示(⟶表示制表符):

dir
⟶ subdir1
⟶ ⟶ file1.ext
⟶ ⟶ subsubdir1
⟶ subdir2
⟶ ⟶ subsubdir2
⟶ ⟶ ⟶ file2.ext

如果是代码表示,上面的文件系统可以写为 "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"'\n''\t' 分别是换行符和制表符。

文件系统中的每个文件和文件夹都有一个唯一的 绝对路径 ,即必须打开才能到达文件/目录所在位置的目录顺序,所有路径用 '/' 连接。上面例子中,指向 file2.ext绝对路径"dir/subdir2/subsubdir2/file2.ext" 。每个目录名由字母、数字和/或空格组成,每个文件名遵循 name.extension 的格式,其中 name 和 extension 由字母、数字和 / 或空格组成。

给定一个以上述格式表示文件系统的字符串 input ,返回文件系统中 指向 文件 的 最长绝对路径 的长度 。 如果系统中没有文件,返回 0

提示:

  • 1input.length1041 \leqslant input.length \leqslant 10^4
  • input 可能包含小写或大写的英文字母,一个换行符 '\n',一个制表符 '\t',一个点 '.',一个空格 ' ',和数字。

示例 1:

dir1.jpg

输入:input = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
输出:20
解释:只有一个文件,绝对路径为 "dir/subdir2/file.ext" ,路径长度 20

示例 2:

dir2.jpg

输入:input = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
输出:32
解释:存在两个文件:
"dir/subdir1/file1.ext" ,路径长度 21
"dir/subdir2/subsubdir2/file2.ext" ,路径长度 32
返回 32 ,因为这是最长的路径

示例 3:

输入:input = "a"
输出:0
解释:不存在任何文件

示例 4:

输入:input = "file1.txt\nfile2.txt\nlongfile.txt"
输出:12
解释:根目录下有 3 个文件
因为根目录中任何东西的绝对路径只是名称本身,所以答案是 "longfile.txt" ,路径长度为 12

整理题意

题目给了一个长度不超过 10410^4 的表示文件系统的字符串,让我们返回文件系统中 指向 文件 的 最长绝对路径 的长度 。 如果系统中没有文件,返回 0

解题思路分析

通过题目描述,我们得知需要找到路径最长的文件。

需要注意的是这个路径并不是表示路径层数最多的,而是需要加上文件夹和文件名的长度来判断是否是最长的路径长度,例如我们通过 示例2 中的解释可以看到:

输入:input = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
输出:32
解释:存在两个文件:
"dir/subdir1/file1.ext" ,路径长度 21
"dir/subdir2/subsubdir2/file2.ext" ,路径长度 32
返回 32 ,因为这是最长的路径

如果这里增加 file1.ext 的文件名长度使其超过 file2.ext 路径总长度的话就要输出 file1.ext 的路径总长度了:

"dir/subdir1/xxxxxxxxxxxxxxfile1.ext" ,路径长度 35
"dir/subdir2/subsubdir2/file2.ext" ,路径长度 32
返回 35 ,因为这是最长的路径

所以路径长度是和路径层数没有关系的,这里是需要注意得。

我们很容易联想到平时在电脑中浏览文件夹中的文件的场景,不就是上面那一行路径吗:

微信图片_20220421145710.png

点击一下,更像了!

微信截图_20220421145752.png

我们可以从题目给我们的字符串 input 入手,既然是要找这个文件所在路径的路径名最长长度,那我们 用栈模拟进入文件夹和返回上一层文件夹的操作,并且用变量维护当前所在的层数以及路径长度,同时维护带 '.' 字符文件的最大路径长度 ,这就是我们的 核心思想

这里需要注意题目给我们的字符串中 '\n''\t' 都表示一个字符,不要当作

具体实现

通过观察题目给我们的字符串 input 以及文本格式:

dir
⟶ subdir1
⟶ ⟶ file1.ext
⟶ ⟶ subsubdir1
⟶ subdir2
⟶ ⟶ subsubdir2
⟶ ⟶ ⟶ file2.ext

可以发现我们可以通过 '\n' 字符划分每一个新的文件或文件夹,用 '\t' 字符确定层数。

这里我们用 来模拟当前所在路径:

  1. 遇到新的一个文件或文件夹,确定其所在层数:
    • 如果层数大于 > 栈顶的 文件夹 所在层数,表示进入该文件夹,我们将其压入栈。(注意此时栈顶只可能是文件夹)
    • 如果层数等于 = 栈顶的 文件夹文件 ,表示遍历到同层的下一个文件夹或文件,对于栈顶的 文件夹 ,之后我们不会用上,也不会再进入,所以可以直接弹出,将新的文件夹或文件压入栈。
    • 如果层数小于 < 栈顶的 文件夹文件 ,表示返回上一层,此时需要将栈顶的 文件夹文件 弹出,直至栈顶的 文件夹文件 与当前文件或文件夹同层。
  2. 从头到尾遍历每一个新的文件或文件夹即可,在模拟过程中我们需要不断维护当前路径长度 len 、当前层数 now 、上一个文件所在层数 last 以及最终答案的最长路径 ans

复杂度分析

  • 时间复杂度:O(n)O(n),其中 n 是字符串 input 的长度。需要遍历一遍字符串,因此时间复杂度为 O(n)O(n)
  • 空间复杂度:O(n)O(n),其中 n 是字符串 input 的长度。需用栈保存当前路径中每个文件夹的长度,当前路径的最大深度为 n,因此栈中最多有 n 个元素,因此空间复杂度为 O(n)O(n)

代码实现

class Solution {
public:
    int lengthLongestPath(string input) {
        //n表示字符串长度,i表示当前遍历的下标
        int n = input.length();
        int i = 0;
        //len表示当前路径长度,now记录当前层数
        int len = 0;
        int now = 0;
        //last记录上一个文件或文件夹的长度,初始化为-1,表示第一个文件或文件夹没有上一个。
        int last = -1;
        //ans为记录最长的路径长度
        int ans = 0;
        //用栈模拟遍历,记录最长路径
        stack<string> s;
        while(s.size()) s.pop();
        while(i < n){
            //换行符开头
            if(input[i] == '\n'){
                //新的一层,记录上一层深度
                last = now;
                now = 0;
                i++;
            }
            //制表符开头
            else if(input[i] == '\t'){
                now++;
                i++;
            }
            //字母开头空格和数字
            else {
                //判断是文件夹还是文件
                string temp = "";
                bool isfile = false;
                while(i < n && input[i] != '\n'){
                    if(input[i] == '.') isfile = true;
                    temp += input[i];
                    i++;
                }
                //如果与上一个同层
                if(now == last){
                    //直接替换
                    len -= s.top().length();
                    s.pop();
                    s.push(temp);
                    len += temp.length();
                }
                else if(now > last){
                    //加层
                    s.push(temp);
                    len += temp.length();
                }
                else{
                    //now < last 退层
                    while(now < last){
                        len -= s.top().length();
                        s.pop();
                        last--;
                    }
                    //退到同层替换
                    len -= s.top().length();
                    s.pop();
                    s.push(temp);
                    len += temp.length();
                }
                //判断是否是文件
                if(isfile){
                    ans = max(ans, len + now);
                }
            }
        }
        return ans;
    }
};

总结

该题核心思想在于用栈模拟进入文件夹和返回上一层文件夹的操作,并且用变量维护当前所在的层数以及路径长度,同时维护带 '.' 字符文件的最大路径长度,同时需要注意题目中没有描述清楚的细节问题。关键在于根据题目数据范围提示(input 可能包含小写或大写的英文字母,一个换行符 '\n',一个制表符 '\t',一个点 '.',一个空格 ' ',和数字)做好分类处理即可。在编写代码的时候可以多写注释,确保每种情况不重不漏。


结束语

要立志高远,但不能急功近利;要行动迅速,去不可贪图速成。聪明人会下笨功夫,大事业来自于小进步。以只争朝夕的心态,做久久为功的准备。踏实的你,已经很了不起!