一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
题目链接:388. 文件的最长绝对路径
题目描述
假设有一个同时存储文件和目录的文件系统。下图展示了文件系统的一个示例:
这里将 dir 作为根目录中的唯一目录。dir 包含两个子目录 subdir1 和 subdir2 。subdir1 包含文件 file1.ext 和子目录 subsubdir1;subdir2 包含子目录 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。
提示:
input可能包含小写或大写的英文字母,一个换行符'\n',一个制表符'\t',一个点'.',一个空格' ',和数字。
示例 1:
输入:input = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
输出:20
解释:只有一个文件,绝对路径为 "dir/subdir2/file.ext" ,路径长度 20
示例 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 ,因为这是最长的路径
示例 3:
输入:input = "a"
输出:0
解释:不存在任何文件
示例 4:
输入:input = "file1.txt\nfile2.txt\nlongfile.txt"
输出:12
解释:根目录下有 3 个文件。
因为根目录中任何东西的绝对路径只是名称本身,所以答案是 "longfile.txt" ,路径长度为 12
整理题意
题目给了一个长度不超过 的表示文件系统的字符串,让我们返回文件系统中 指向 文件 的 最长绝对路径 的长度 。 如果系统中没有文件,返回 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 ,因为这是最长的路径所以路径长度是和路径层数没有关系的,这里是需要注意得。
我们很容易联想到平时在电脑中浏览文件夹中的文件的场景,不就是上面那一行路径吗:
点击一下,更像了!
我们可以从题目给我们的字符串 input 入手,既然是要找这个文件所在路径的路径名最长长度,那我们 用栈模拟进入文件夹和返回上一层文件夹的操作,并且用变量维护当前所在的层数以及路径长度,同时维护带 '.' 字符文件的最大路径长度 ,这就是我们的 核心思想 。
这里需要注意题目给我们的字符串中
'\n'和'\t'都表示一个字符,不要当作
具体实现
通过观察题目给我们的字符串 input 以及文本格式:
dir
⟶ subdir1
⟶ ⟶ file1.ext
⟶ ⟶ subsubdir1
⟶ subdir2
⟶ ⟶ subsubdir2
⟶ ⟶ ⟶ file2.ext
可以发现我们可以通过 '\n' 字符划分每一个新的文件或文件夹,用 '\t' 字符确定层数。
这里我们用 栈 来模拟当前所在路径:
- 遇到新的一个文件或文件夹,确定其所在层数:
- 如果层数大于
>栈顶的 文件夹 所在层数,表示进入该文件夹,我们将其压入栈。(注意此时栈顶只可能是文件夹) - 如果层数等于
=栈顶的 文件夹 或 文件 ,表示遍历到同层的下一个文件夹或文件,对于栈顶的 文件夹 ,之后我们不会用上,也不会再进入,所以可以直接弹出,将新的文件夹或文件压入栈。 - 如果层数小于
<栈顶的 文件夹 或 文件 ,表示返回上一层,此时需要将栈顶的 文件夹 或 文件 弹出,直至栈顶的 文件夹 或 文件 与当前文件或文件夹同层。
- 如果层数大于
- 从头到尾遍历每一个新的文件或文件夹即可,在模拟过程中我们需要不断维护当前路径长度
len、当前层数now、上一个文件所在层数last以及最终答案的最长路径ans。
复杂度分析
- 时间复杂度:,其中
n是字符串input的长度。需要遍历一遍字符串,因此时间复杂度为 。 - 空间复杂度:,其中
n是字符串input的长度。需用栈保存当前路径中每个文件夹的长度,当前路径的最大深度为n,因此栈中最多有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',一个点 '.',一个空格 ' ',和数字)做好分类处理即可。在编写代码的时候可以多写注释,确保每种情况不重不漏。
结束语
要立志高远,但不能急功近利;要行动迅速,去不可贪图速成。聪明人会下笨功夫,大事业来自于小进步。以只争朝夕的心态,做久久为功的准备。踏实的你,已经很了不起!