题目
标题和出处
标题:文件夹操作日志搜集器
难度
2 级
题目描述
要求
每当用户执行变更文件夹操作时,LeetCode 文件系统都会保存一条日志记录。
下面给出对变更操作的说明:
- "../" \texttt{"../"} "../":移动到当前文件夹的父文件夹。如果已经在主文件夹下,则继续停留在当前文件夹。
- "./" \texttt{"./"} "./":继续停留在当前文件夹。
- "x/" \texttt{"x/"} "x/":移动到名为 x \texttt{x} x 的子文件夹中。题目数据保证总是存在文件夹 x \texttt{x} x。
给你一个字符串列表 logs \texttt{logs} logs,其中 logs[i] \texttt{logs[i]} logs[i] 是用户在第 i \texttt{i} i 步执行的操作。
文件系统启动时位于主文件夹,然后执行 logs \texttt{logs} logs 中的操作。
执行完所有变更文件夹操作后,请你找出返回主文件夹所需的最小步数。
示例
示例 1:
输入:
logs
=
["d1/","d2/","../","d21/","./"]
\texttt{logs = ["d1/","d2/","../","d21/","./"]}
logs = ["d1/","d2/","../","d21/","./"]
输出:
2
\texttt{2}
2
解释:执行
"../"
\texttt{"../"}
"../" 操作变更文件夹
2
\texttt{2}
2 次,即可回到主文件夹。
示例 2:
输入:
logs
=
["d1/","d2/","./","d3/","../","d31/"]
\texttt{logs = ["d1/","d2/","./","d3/","../","d31/"]}
logs = ["d1/","d2/","./","d3/","../","d31/"]
输出:
3
\texttt{3}
3
示例 3:
输入:
logs
=
["d1/","../","../","../"]
\texttt{logs = ["d1/","../","../","../"]}
logs = ["d1/","../","../","../"]
输出:
0
\texttt{0}
0
数据范围
- 1 ≤ logs.length ≤ 10 3 \texttt{1} \le \texttt{logs.length} \le \texttt{10}^\texttt{3} 1≤logs.length≤103
- 2 ≤ logs[i].length ≤ 10 \texttt{2} \le \texttt{logs[i].length} \le \texttt{10} 2≤logs[i].length≤10
- logs[i] \texttt{logs[i]} logs[i] 包含小写英文字母,数字, ‘.’ \texttt{`.'} ‘.’ 和 ‘/’ \texttt{`/'} ‘/’
- logs[i] \texttt{logs[i]} logs[i] 符合语句中描述的格式
- 文件夹名称由小写英文字母和数字组成
解法一
思路和算法
根据题目描述,每一步操作都是有效的操作,因此只要记录每一步操作之后所在的文件夹的路径,即可知道返回主文件夹所需的步数。文件夹的路径为从主文件夹到当前文件夹需要经过的全部文件夹。
可以使用栈记录文件夹的路径,栈顶元素为当前文件夹。
对于每种变更操作,分别对栈进行不同的操作:
- “../" \text{``../"} “../":如果栈不为空,则将栈顶元素出栈,新的栈顶元素即为当前文件夹的父文件夹。如果栈为空,则不进行任何操作。
- “./" \text{``./"} “./":不进行任何操作。
- “x/" \text{``x/"} “x/":将 “x/" \text{``x/"} “x/" 入栈,新的栈顶元素即为名为 x \text{x} x 的子文件夹。
执行完所有变更文件夹操作后,如果栈不为空,则需要将栈内元素依次出栈,直到栈为空时,返回主文件夹,因此返回主文件夹所需的最小步数即为出栈次数。其实并不需要真正将元素出栈,出栈次数等同于栈内元素个数,栈内元素个数即为返回主文件夹所需的最小步数。
代码
class Solution {
public int minOperations(String[] logs) {
Deque<String> stack = new ArrayDeque<String>();
int length = logs.length;
for (int i = 0; i < length; i++) {
String log = logs[i];
if ("../".equals(log)) {
if (!stack.isEmpty()) {
stack.pop();
}
} else if ("./".equals(log)) {
continue;
} else {
stack.push(log);
}
}
return stack.size();
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 logs \textit{logs} logs 的长度。需要遍历数组 logs \textit{logs} logs 一次,这里假设数组 logs \textit{logs} logs 中的每个元素的长度都是常数。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 logs \textit{logs} logs 的长度。空间复杂度主要取决于栈空间,栈最多包含 n n n 个元素,这里假设数组 logs \textit{logs} logs 中的每个元素的长度都是常数。
解法二
思路和算法
由于返回主文件夹所需的最小步数只和栈内元素个数有关,而和元素内容无关,因此也可以不用栈,而是使用计数的方式计算返回主文件夹所需的最小步数。
具体做法是,使用 operations \textit{operations} operations 记录返回主文件夹所需的最小步数,初始时 operations = 0 \textit{operations} = 0 operations=0。出栈操作对应将 operations \textit{operations} operations 减 1 1 1,入栈操作对应将 operations \textit{operations} operations 加 1 1 1,任何时候 operations \textit{operations} operations 都是非负整数。执行完所有变更文件夹操作后, operations \textit{operations} operations 即为返回主文件夹所需的最小步数。
代码
class Solution {
public int minOperations(String[] logs) {
int operations = 0;
int length = logs.length;
for (int i = 0; i < length; i++) {
String log = logs[i];
if ("../".equals(log)) {
operations = Math.max(operations - 1, 0);
} else if ("./".equals(log)) {
continue;
} else {
operations++;
}
}
return operations;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 logs \textit{logs} logs 的长度。需要遍历数组 logs \textit{logs} logs 一次,这里假设数组 logs \textit{logs} logs 中的每个元素的长度都是常数。
-
空间复杂度: O ( 1 ) O(1) O(1)。