Description
Suppose we have a file system that stores both files and directories. An example of one system is represented in the following picture:
Here, we have dir
as the only directory in the root. dir
contains two subdirectories, subdir1
and subdir2
. subdir1
contains a file file1.ext
and subdirectory subsubdir1
. subdir2
contains a subdirectory subsubdir2
, which contains a file file2.ext
.
In text form, it looks like this (with ⟶ representing the tab character):
dir
⟶ subdir1
⟶ ⟶ file1.ext
⟶ ⟶ subsubdir1
⟶ subdir2
⟶ ⟶ subsubdir2
⟶ ⟶ ⟶ file2.ext
If we were to write this representation in code, it will look like this: "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
. Note that the '\n'
and '\t'
are the new-line and tab characters.
Every file and directory has a unique absolute path in the file system, which is the order of directories that must be opened to reach the file/directory itself, all concatenated by '/'s
. Using the above example, the absolute path to file2.ext
is "dir/subdir2/subsubdir2/file2.ext"
. Each directory name consists of letters, digits, and/or spaces. Each file name is of the form name.extension
, where name
and extension
consist of letters, digits, and/or spaces.
Given a string input
representing the file system in the explained format, return the length of the longest absolute path to a file in the abstracted file system. If there is no file in the system, return 0
.
Examples:
Example 1:
Input: input = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
Output: 20
Explanation: We have only one file, and the absolute path is "dir/subdir2/file.ext" of length 20.
Example 2:
Input: input = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
Output: 32
Explanation: We have two files:
"dir/subdir1/file1.ext" of length 21
"dir/subdir2/subsubdir2/file2.ext" of length 32.
We return 32 since it is the longest absolute path to a file.
Example 3:
Input: input = "a"
Output: 0
Explanation: We do not have any files, just a single directory named "a".
Solution in Python
Approach:
- Parse the File System:
- Each line in the input string represents either a file or directory.
- The level of each file or directory is determined by the number of preceding
\t
characters.
- Track Path Lengths by Level:
- Use a dictionary,
path_lengths
, to store the cumulative path length up to each level. - When we encounter a directory, we update
path_lengths
at that level with the length of the path up to that directory. - When we encounter a file, we compute the total path length for that file by summing up the lengths from previous levels.
- Use a dictionary,
- Identify and Track the Longest Path:
- As we parse each line, if it represents a file (determined by the presence of a dot,
.
), we calculate the absolute path length to that file and compare it with the maximum length found so far.
- As we parse each line, if it represents a file (determined by the presence of a dot,
- Edge Cases:
- If there are no files in the system, return 0.
- Handle nested directories and files accurately based on the tab level.
class Solution:
def lengthLongestPath(self, input: str) -> int:
# Dictionary to store cumulative path lengths at each depth level
path_lengths = {0: 0}
max_length = 0
# Split the input by lines, each line representing a file or directory
for line in input.splitlines():
# Determine the depth level by counting '\t'
depth = line.count('\t')
# Remove the '\t' characters to get the actual name of the file or directory
name = line.lstrip('\t')
if '.' in name:
# It's a file, calculate the absolute path length
# Path length is the sum of lengths up to the parent directory + length of the current file + '/' separators
current_length = path_lengths[depth] + len(name)
max_length = max(max_length, current_length)
else:
# It's a directory, update the cumulative path length at this level
# +1 accounts for the '/' separator after the directory name
path_lengths[depth + 1] = path_lengths[depth] + len(name) + 1
return max_length
Explanation of the Code:
- Dictionary Initialization:
path_lengths = {0: 0}
initializes the cumulative path length to0
at the root level (level 0).
- Looping through Each Line:
- We iterate over each line in the input string split by newline characters. Each line represents either a file or a directory.
- Determine Depth Level:
- The depth (or level) is determined by counting the number of
\t
characters. - We then strip the
\t
characters from the line to get the actual name of the file or directory.
- The depth (or level) is determined by counting the number of
- Handling Files:
- If
name
contains a dot (.
), it’s a file. - We calculate the absolute path length to this file as
path_lengths[depth] + len(name)
, wherepath_lengths[depth]
is the cumulative path length up to this level. - We update
max_length
if the computed path length for this file is longer than the currentmax_length
.
- If
- Handling Directories:
- If
name
is a directory, we store the cumulative path length up to this directory inpath_lengths[depth + 1]
by adding the current length atdepth
pluslen(name) + 1
(the extra1
accounts for the/
separator).
- If
- Return Result:
- After processing all lines,
max_length
will contain the length of the longest absolute path to a file. If no files were encountered, it will remain0
.
- After processing all lines,
Solution in C++
class Solution {
public:
int lengthLongestPath(string input) {
// Stack to keep track of the current length of each directory level
stack<int> st;
// Variable to store the maximum length of a file path
int maxLength = 0;
// Variable to store the current path length
int currLength = 0;
// Stream to iterate through each line of the input
istringstream ss(input);
string line;
// Iterate through each line in the input
while (getline(ss, line)) {
// Count the number of '\t' characters at the beginning of the line to determine the depth level
int depth = 0;
while (depth < line.size() && line[depth] == '\t') depth++;
// Remove all '\t' characters to get the actual name of the file or directory
line = line.substr(depth);
// Adjust the stack to match the current depth
// If the depth of the current file/directory is less than the stack size,
// it means we are going up in the directory structure, so we need to pop
// elements from the stack to match the depth.
while (st.size() > depth) {
currLength -= st.top();
st.pop();
}
// Push the length of the current directory/file onto the stack
// Add 1 for the '/' that separates directories in the path
int length = line.size() + 1;
st.push(length);
currLength += length;
// Check if the current line represents a file (it contains a '.')
if (line.find('.') != string::npos) {
// Update the maximum length if the current file path is longer
maxLength = max(maxLength, currLength - 1); // Subtract 1 to exclude the trailing '/'
}
}
// Return the maximum length of the file path
return maxLength;
}
};
Solution in Javascript
var lengthLongestPath = function(input) {
// Split the input by new lines to process each line individually
const paths = input.split('\n');
// Dictionary to keep track of the length of the current path at each depth level
const pathLengthAtDepth = {0: 0}; // Initialize depth 0 with 0 length
let maxLength = 0; // This will store the maximum length of a file path found
// Loop through each path component (directory or file) in the input
for (let path of paths) {
// Find the current depth by counting the '\t' characters
const depth = path.lastIndexOf('\t') + 1;
// Remove the '\t' characters to get the actual name of the file or directory
const name = path.slice(depth);
// Check if this is a file (contains a dot) or a directory (no dot)
if (name.includes('.')) {
// If it's a file, calculate the full path length
const filePathLength = pathLengthAtDepth[depth] + name.length;
// Update maxLength if this file's path is longer than previous paths
maxLength = Math.max(maxLength, filePathLength);
} else {
// If it's a directory, update the path length at the next depth level
pathLengthAtDepth[depth + 1] = pathLengthAtDepth[depth] + name.length + 1;
// The "+1" is for the '/' added between directories/files in the path
}
}
// Return the longest file path length found, or 0 if no file was found
return maxLength;
};
Solution in Java
class Solution {
public int lengthLongestPath(String input) {
// Split the input by newline character '\n' to separate each line
String[] paths = input.split("\n");
// Stack to keep track of the length of directories at each level
int[] stack = new int[paths.length + 1];
// Variable to store the maximum length of any absolute path found
int maxLength = 0;
// Iterate through each line (file or directory)
for (String path : paths) {
// Find the depth (level) by counting the number of '\t' characters
int level = path.lastIndexOf("\t") + 1;
// Calculate the actual length of the current directory/file name
int lengthWithoutTabs = path.length() - level;
// Calculate the total length of the path up to the current directory/file
stack[level + 1] = stack[level] + lengthWithoutTabs + 1; // +1 for '/' separator
// Check if the current path is a file by looking for a '.' character in its name
if (path.contains(".")) {
// If it's a file, calculate the full path length and update maxLength if necessary
maxLength = Math.max(maxLength, stack[level + 1] - 1); // -1 to remove the trailing '/'
}
}
// Return the maximum length found, or 0 if no files are present
return maxLength;
}
}