The "Crawler Log Folder" problem requires you to simulate navigating a file system using a sequence of folder change logs. You are given a list of strings, logs
, where each string represents a folder operation:
"../"
: Move to the parent folder (if not already at the root)."./"
: Stay in the current folder."x/"
: Move into a child folder named x
(where x
is any valid folder name).logs
and return the minimum number of steps needed to return to the root folder after all operations are completed.
'/'
.
At first glance, you might think of simulating the folder structure using a stack, pushing and popping folder names as you traverse. Each "../"
would pop a folder (if possible), each "./"
would do nothing, and each "x/"
would push a new folder onto the stack.
However, since the problem only asks for the minimum steps to return to the root, we don't need to keep track of actual folder names. We only need to count how deep we are in the folder hierarchy. This can be tracked with a single integer variable representing the depth.
This insight allows us to optimize the solution by avoiding unnecessary data structures and focusing only on the folder depth.
Let's break down the solution step by step:
depth = 0
since we begin at the root folder.logs
:
"../"
and depth > 0
, decrement depth
by 1 (move up one level)."./"
, do nothing (stay at the current level)."x/"
), increment depth
by 1 (move into a subfolder).depth
represents how many levels deep you are from the root. This is the minimum number of steps needed to return to the root folder.We use a simple integer counter because all we care about is the current "distance" from the root, not the actual path taken.
Example Input:
logs = ["d1/", "d2/", "../", "d21/", "./"]
Let's process each operation step by step:
"d1/"
: Move into "d1" → depth = 1"d2/"
: Move into "d2" → depth = 2"../"
: Move up to parent (from "d2" to "d1") → depth = 1"d21/"
: Move into "d21" → depth = 2"./"
: Stay in current folder → depth = 2class Solution:
def minOperations(self, logs):
depth = 0
for log in logs:
if log == "../":
if depth > 0:
depth -= 1
elif log == "./":
continue
else:
depth += 1
return depth
class Solution {
public:
int minOperations(vector<string>& logs) {
int depth = 0;
for (const string& log : logs) {
if (log == "../") {
if (depth > 0) depth--;
} else if (log == "./") {
continue;
} else {
depth++;
}
}
return depth;
}
};
class Solution {
public int minOperations(String[] logs) {
int depth = 0;
for (String log : logs) {
if (log.equals("../")) {
if (depth > 0) depth--;
} else if (log.equals("./")) {
continue;
} else {
depth++;
}
}
return depth;
}
}
var minOperations = function(logs) {
let depth = 0;
for (const log of logs) {
if (log === "../") {
if (depth > 0) depth--;
} else if (log === "./") {
continue;
} else {
depth++;
}
}
return depth;
};
Brute-force approach:
If we used a stack to keep track of folder names, the time complexity would still be O(n)
(where n
is the number of logs), but the space complexity would be up to O(n)
in the worst case (if we never move up).
Optimized approach:
O(n)
— We process each log exactly once.O(1)
— We use only a single integer variable to track the depth, regardless of input size.The key insight is that we only need to track how deep we are in the directory tree, not the full path. By using a simple counter, we efficiently solve the problem with minimal code and optimal performance. This approach demonstrates the power of reducing a problem to its core requirements and avoiding unnecessary complexity.