#LC388. 文件的最长绝对路径
文件的最长绝对路径
你好,同学。欢迎来到 NOI 专题训练。
今天我们要挑战的是一个非常有意思的模拟题:文件的最长绝对路径。这道题虽然来源于工程应用(文件系统遍历),但其内核是考察选手对树的深度优先搜索(DFS)、栈(Stack)以及复杂字符串解析的综合掌控能力。
一、 预备知识点
在挑战本题前,请确保你已经掌握:
- 栈(Stack)或前缀和思想:用于维护当前路径的累积长度。
- 字符串解析(String Parsing):
- 识别转义字符
\n(换行,表示新文件/目录的开始)。 - 识别转义字符
\t(制表符,表示当前文件/目录的深度)。
- 识别转义字符
- 深度优先搜索逻辑:理解目录结构的层次感,每一层目录的长度都依赖于上一层。
二、 NOI 竞赛题目描述
题目名称:文件的最长绝对路径 (Longest Absolute File Path) 时间限制:1.0s 内存限制:256MB
【问题描述】
假设文件系统可以用字符串表示。例如,字符串 "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext" 表示:
dir
subdir1
subdir2
file.ext
这里 dir 是根目录,包含两个子目录 subdir1 和 subdir2。subdir2 包含一个文件 file.ext。
我们感兴趣的是文件系统中某个文件(即名称中包含 . 的项)的绝对路径的长度。在上面的例子中,绝对路径是 "dir/subdir2/file.ext",其长度为 。
给你一个表示文件系统的字符串 input,返回文件系统中 最长绝对路径 的长度。如果系统中没有文件,返回 。
注意:
- 名称中包含
.的项被视为文件,否则视为目录。 \n和\t仅占一个字符长度(在输入中可能以转义字符形式出现)。
【输入格式】
输入仅一行,包含一个长度为 的字符串 。
(注意:在 NOI 评测中,输入字符串可能包含空格,建议使用 getline 或处理转义逻辑)
【输出格式】 输出一个整数,表示最长的绝对路径长度。
【样例输入 1】
dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext
【样例输出 1】
20
【样例输入 2】
dir\n\tsubdir1\n\t\tsubdir11\n\tsubdir2\n\t\tsubdir21\n\t\t\tfile.ext
【样例输出 2】
25
【数据规模与约定】
input由英文字母、数字、空格、'.'、'\n' 和 '\t' 组成。
三、 启发式思路引导:草稿纸上的推演
请拿出草稿纸,我们通过“层级长度累加法”来思考:
1. 核心矛盾:如何知道当前文件在哪一层?
- 观察:
\t的数量直接决定了深度。0 个\t是第 0 层(根),1 个\t是第 1 层。 - 启发:我们可以维护一个数组(或栈)
depth_length,其中depth_length(i)表示第i层目录的累积绝对路径长度。
2. 草稿纸模拟过程(以样例 1 为例)
字符串:dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext
- 遇到 "dir":
- 深度:0
- 名字长度:3
- 当前是目录。记录
level_len(0) = 3。
- 遇到 "\tsubdir1":
- 深度:1(通过 1 个
\t识别) - 名字长度:7
- 绝对路径:
level_len(0)+/+subdir1。 - 是目录。记录
level_len(1) = 11。
- 深度:1(通过 1 个
- 遇到 "\tsubdir2":
- 深度:1
- 名字长度:7
- 绝对路径:
level_len(0)+/+subdir2。 - 是目录。覆盖记录
level_len(1) = 11。
- 遇到 "\t\tfile.ext":
- 深度:2
- 名字长度:8
- 绝对路径:
level_len(1)+/+file.ext。 - 关键:含有
.,它是文件!更新全局最大值ans = max(0, 20) = 20。
四、 算法流程图(伪代码逻辑)
在 C++14 实现中,由于字符串可能很大,建议一次性扫描或使用迭代器。
graph TD
Start(开始扫描 input 字符串) --> Init(初始化 ans=0, level_len 数组)
Init --> Loop{是否到达末尾}
Loop -- 否 --> FindLevel(计算当前行开头的 tab 数量记为 depth)
FindLevel --> GetName(提取文件名或目录名记为 name)
GetName --> CheckFile{name 中是否包含点号}
CheckFile -- 是 --> UpdateAns(计算当前总长度并更新 ans)
CheckFile -- 否 --> UpdateLen(更新 level_len_at_depth 并存入数组)
UpdateAns --> Loop
UpdateLen --> Loop
Loop -- 是 --> Finish(返回 ans)
subgraph Length_Calc
UpdateAns_Logic(总长 = 上一层长度 + 1加上当前名字长度)
end
五、 复杂度分析与优化建议
- 时间复杂度:。
- 我们只需要对字符串进行一遍线性扫描。
- 虽然字符串切分可能产生临时对象,但在 C++ 中可以通过索引
start, end避开昂贵的字符串拷贝。
- 空间复杂度:。
- 最坏情况下深度可以达到 (每一层只有一个字母),我们需要一个大小为 的数组来记录每一层的长度。
优化建议:
- 快速读入:在 NOI 竞赛中,如果字符串包含
\n这种字符,直接用cin >> s会在换行处停止。请使用while(getline(cin, s))或者通过getchar()逐字符解析。 - 原地解析:不要使用
split函数(C++ 标准库没有自带高效的 split),通过双指针直接在原串上计算\t数量和名字长度。
六、 读题关键词总结
- "\n" 与 "\t":这是文件树的“导航仪”,决定了逻辑上的入栈和出栈。
- "包含 '.'":这是触发结算的唯一条件,只有文件计入答案,目录不计入。
- "绝对路径":别忘了层级之间的斜杠
/,它也占 1 个字符长度(通常在计算第i层长度时,如果i > 0,则需要+1)。
教练寄语: 这道题的核心在于状态维护。你不需要真的去构建一棵树,只需要记住“当前通往根的路径长是多少”。这种“化树为线”的思维,是解决高级模拟题的重要技巧。去尝试写出你的 C++ 代码吧!