Longest Absolute File Path
MedPrompt
Approaches
2 approaches with complexity analysis and trade-offs.
This approach iterates through each entry in the file system. When a file is found, it reconstructs its entire absolute path by searching backwards for its parent directories, level by level, until it reaches the root. The length of this reconstructed path is then calculated. This process is repeated for every file in the system.
Algorithm
- Split the input string by the newline character
\nto get an array of all file/directory entries. - Initialize a variable
maxLengthto 0. - Iterate through each entry
swith its indexiin the array. - If the entry
sdoes not contain a.(i.e., it's a directory), skip it. - If it is a file, determine its depth
currentLevelby counting the leading\tcharacters. - Calculate the current path length, starting with the length of the file's name.
- Iterate backwards from index
i-1down to 0 to find its ancestors. - In the backward scan, look for an entry whose depth is exactly
currentLevel - 1. This is the parent. - Once the parent is found, add its name length plus 1 (for the
/separator) to the current path length. - Decrement
currentLeveland continue the backward scan to find the grandparent, and so on, until the root (level 0) is processed. - After building the full path length for the current file, update
maxLength = max(maxLength, currentPathLength). - Return
maxLengthafter checking all entries.
Walkthrough
The core idea is to treat the problem as a search task. For every line that represents a file, we initiate a backward search through the preceding lines to find its hierarchical parents. The depth of each entry, determined by the number of tab characters, guides this search.
Here is the algorithm:
- Split the input string by the newline character
\nto get an array of all file/directory entries. - Initialize a variable
maxLengthto 0. - Iterate through each entry
swith its indexiin the array. - If the entry
sdoes not contain a.(i.e., it's a directory), skip it. - If it is a file, determine its depth
currentLevelby counting the leading\tcharacters. - Calculate the current path length, starting with the length of the file's name.
- Iterate backwards from index
i-1down to 0 to find its ancestors. - In the backward scan, look for an entry whose depth is exactly
currentLevel - 1. This is the parent. - Once the parent is found, add its name length plus 1 (for the
/separator) to the current path length. - Decrement
currentLeveland continue the backward scan to find the grandparent, and so on, until the root (level 0) is processed. - After building the full path length for the current file, update
maxLength = max(maxLength, currentPathLength). - Return
maxLengthafter checking all entries.
class Solution { public int lengthLongestPath(String input) { String[] paths = input.split("\n"); int maxLength = 0; for (int i = 0; i < paths.length; i++) { String currentPathStr = paths[i]; // We only care about paths to files. if (!currentPathStr.contains(".")) { continue; } int currentLevel = getLevel(currentPathStr); // Length of the file name itself. int currentLength = currentPathStr.length() - currentLevel; int parentLevel = currentLevel - 1; // Search backwards for parent directories. for (int j = i - 1; j >= 0 && parentLevel >= 0; j--) { String potentialParent = paths[j]; if (getLevel(potentialParent) == parentLevel) { // Add parent's name length + 1 for the '/'. currentLength += (potentialParent.length() - parentLevel) + 1; parentLevel--; } } maxLength = Math.max(maxLength, currentLength); } return maxLength; } // Helper to count the level (number of tabs). private int getLevel(String s) { return s.lastIndexOf('\t') + 1; }}Complexity
Time
O(L^2), where L is the number of lines (files/directories). For each file (of which there can be up to L), we may scan backwards through all L previous lines.
Space
O(N), where N is the length of the input string. This space is required to store the array of strings after splitting the input.
Trade-offs
Pros
Conceptually straightforward, as it directly mimics the process of building a path for each file.
Does not require complex data structures, relying only on array indexing and loops.
Cons
Highly inefficient due to redundant computations. The path for a common directory like
diris recalculated for every file under it.The nested loop structure leads to poor time complexity, making it unsuitable for large inputs.
A much more efficient approach is to traverse the file system entries in a single pass. We use an auxiliary data structure (like an array or a hash map) to keep track of the path length at each depth level. When we process an entry at a certain level, we can instantly find the length of its parent's path and extend it, avoiding any recalculation. This is analogous to a pre-order traversal of the file system tree.
Algorithm
- Initialize
maxLength = 0. - Create an array,
pathLengths, to store the length of the path at each level.pathLengths[level + 1]will store the length of the path to the directory atlevel, including the trailing slash. - Initialize
pathLengths[0] = 0, representing the length before the root. - Split the input string by
\nto get all entries. - Iterate through each entry
s: a. Determine itslevelby finding the last index of\t(s.lastIndexOf('\t') + 1). b. Calculate the length of the entry's name:nameLength = s.length() - level. c. Retrieve the parent's path length frompathLengths[level]. d. Calculate the current path length:currentPathLength = pathLengths[level] + nameLength. e. If the entrysis a file (contains.), it's a complete path. UpdatemaxLength = max(maxLength, currentPathLength). f. If the entrysis a directory, update thepathLengthsarray for the next level. The length stored for the next level will be the current path length plus 1 for the separator slash:pathLengths[level + 1] = currentPathLength + 1. - Return
maxLength.
Walkthrough
This optimized approach processes the file system hierarchy linearly. It maintains an array where the index corresponds to a depth level, and the value is the length of the path up to that depth. As we iterate through each line, we determine its level, find the length of its parent's path from the array, and calculate the current path's length. This avoids the expensive backward search of the brute-force method.
Here is the algorithm:
- Initialize
maxLength = 0. - Create an array,
pathLengths, to store the length of the path at each level.pathLengths[level + 1]will store the length of the path to the directory atlevel, including the trailing slash. - Initialize
pathLengths[0] = 0, representing the length before the root. - Split the input string by
\nto get all entries. - Iterate through each entry
s: a. Determine itslevelby finding the last index of\t(s.lastIndexOf('\t') + 1). b. Calculate the length of the entry's name:nameLength = s.length() - level. c. Retrieve the parent's path length frompathLengths[level]. d. Calculate the current path length:currentPathLength = pathLengths[level] + nameLength. e. If the entrysis a file (contains.), it's a complete path. UpdatemaxLength = max(maxLength, currentPathLength). f. If the entrysis a directory, update thepathLengthsarray for the next level. The length stored for the next level will be the current path length plus 1 for the separator slash:pathLengths[level + 1] = currentPathLength + 1. - Return
maxLength.
class Solution { public int lengthLongestPath(String input) { String[] paths = input.split("\n"); // pathLengths[i] stores the length of the path to the directory at level i-1 // including the trailing slash. int[] pathLengths = new int[paths.length + 1]; int maxLength = 0; for (String path : paths) { // Determine the level (depth) of the current file/directory. int level = path.lastIndexOf('\t') + 1; // Get the length of the path to the parent directory. int parentPathLength = pathLengths[level]; // Calculate the length of the current file/directory name. int nameLength = path.length() - level; // Calculate the length of the absolute path to the current item. int currentLength = parentPathLength + nameLength; if (path.contains(".")) { // If it's a file, we have a full path. Update max length. // The parentPathLength already includes the necessary slashes. maxLength = Math.max(maxLength, currentLength); } else { // If it's a directory, store its path length for its children to use. // Add 1 for the trailing '/'. pathLengths[level + 1] = currentLength + 1; } } return maxLength; }}Complexity
Time
O(N), where N is the length of the input string. The `split` operation takes O(N), and the loop iterates through each line once. The work inside the loop is effectively constant time on average per character, leading to a total time proportional to N.
Space
O(D), where D is the maximum depth of the file system. This is for the `pathLengths` array. In the worst case, D can be O(L) where L is the number of lines.
Trade-offs
Pros
Optimal time complexity of O(N).
Efficiently calculates lengths without redundant work by processing each entry only once.
Handles the file system structure elegantly using a depth-based state.
Cons
Requires an auxiliary data structure to maintain state across levels.
The logic for updating path lengths based on levels needs to be handled carefully to be correct.
Solutions
Solution
class Solution {public int lengthLongestPath(String input) { int i = 0; int n = input.length(); int ans = 0; Deque<Integer> stack = new ArrayDeque<>(); while (i < n) { int ident = 0; for (; input.charAt(i) == '\t'; i++) { ident++; } int cur = 0; boolean isFile = false; for (; i < n && input.charAt(i) != '\n'; i++) { cur++; if (input.charAt(i) == '.') { isFile = true; } } i++;class Solution {public: int lengthLongestPath(string input) { int i = 0, n = input.size(); int ans = 0; stack<int> stk; while (i < n) { int ident = 0; for (; input[i] == '\t'; ++i) { ++ident; } int cur = 0; bool isFile = false; for (; i < n && input[i] != '\n'; ++i) { ++cur; if (input[i] == '.') { isFile = true; } } ++i;class Solution: # popd while len ( stk ) > 0 and len ( stk ) > ident : stk . pop () if len ( stk ) > 0 : cur += stk [ - 1 ] + 1 # pushd if not isFile : stk . append ( cur ) continue ans = max ( ans , cur ) return ans def lengthLongestPath(self, input: str) -> int: i, n = 0, len(input) ans = 0 stk = [] while i < n: ident = 0 while input[i] == ' \t ': ident += 1 i += 1 cur, isFile = 0, False while i < n and input[i] != ' \n ': cur += 1 if input[i] == '.': isFile = True i += 1 i += 1Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.