Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

388. Longest Absolute File Path - Leetcode Solution

Problem Description

The Longest Absolute File Path problem asks you to compute the length of the longest absolute path to a file within a simulated file system, given as a single string input. The file system is represented by a string, where:

  • Each directory or file is separated by a newline character (\n).
  • Depth is indicated by the number of tab characters (\t) before a name.
  • A file is identified by the presence of a dot (.) in its name (e.g., file.txt).
  • Directories do not contain a dot in their name.
  • The absolute path is constructed by joining directory and file names with the slash (/) character.

The goal is to return the length of the longest absolute path to any file in the system. If there is no file, return 0.

Constraints:

  • Input is a single string representing the file system.
  • All directory and file names are non-empty.
  • Tab characters are used only for indentation, not as part of names.

Thought Process

At first glance, the problem seems to require parsing a string and building a tree-like structure to represent the file system. One might consider constructing an explicit tree, walking it, and tracking the path lengths. However, this could be unnecessarily complex and inefficient.

The key realization is that we don't need to build the whole tree. Instead, we can process each line (directory or file), keep track of the current path length at each depth, and update the longest file path length whenever we encounter a file.

To optimize, we can use a data structure (like a hash map or array) that maps depth levels to the cumulative length of the path up to that level. This allows us to compute the absolute path length for any file efficiently, without backtracking or reconstructing paths.

Solution Approach

Here's a step-by-step breakdown of the algorithm:

  1. Split the input string: Divide the input by newline (\n) to process each directory or file individually.
  2. Determine depth: For each line, count the number of leading tab (\t) characters. This gives the current depth in the directory structure.
  3. Track path lengths: Use a hash map or array (pathlen) where pathlen[depth] stores the total length of the path up to that depth (excluding the current file/directory).
  4. Update path length: For each directory or file, calculate its full path length as pathlen[depth] + len(name) + 1, where +1 accounts for the slash (/).
  5. Check for files: If the current line is a file (contains a dot), update the maximum path length found so far (subtract 1 to remove the extra slash at the end).
  6. Continue for all lines: Repeat the process for each line to ensure all files are considered.
  7. Return the result: After processing all lines, return the maximum path length found.

This approach avoids building a full tree and processes the input in a single pass.

Example Walkthrough

Let's consider a sample input:

    "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
  

After splitting by \n, we get:

  • dir (depth 0)
  • \tsubdir1 (depth 1)
  • \tsubdir2 (depth 1)
  • \t\tfile.ext (depth 2)

We process each line:

  1. dir: depth 0, name "dir"
    • pathlen[0] = 0
    • pathlen[1] = 0 + len("dir") + 1 = 4
  2. subdir1: depth 1, name "subdir1"
    • pathlen[1] = 4 (from above)
    • pathlen[2] = 4 + len("subdir1") + 1 = 12
  3. subdir2: depth 1, name "subdir2"
    • pathlen[1] = 4
    • pathlen[2] = 4 + len("subdir2") + 1 = 12
  4. file.ext: depth 2, name "file.ext"
    • pathlen[2] = 12
    • It's a file, so maxlen = max(0, 12 + len("file.ext")) = 20
The longest absolute file path is "dir/subdir2/file.ext", length 20.

Time and Space Complexity

Brute-force Approach:

  • Building a full tree and traversing all possible paths to files could take O(n^2) time (where n is the length of the input), as reconstructing paths can be costly.
  • Space complexity would also be O(n^2) due to storing all possible paths explicitly.
Optimized Approach (used here):
  • Time Complexity: O(n), where n is the length of the input string, because we process each character at most once.
  • Space Complexity: O(d), where d is the maximum depth of directories (usually much less than n), since we only store the cumulative lengths at each depth.

Summary

The Longest Absolute File Path problem can be solved efficiently by avoiding explicit tree construction. By tracking cumulative path lengths at each depth using a hash map or array, we can process the input in a single pass. This approach is both elegant and efficient, leveraging the structure of the input string to avoid unnecessary complexity. The main insight is to map depth to path length and update the maximum whenever a file is encountered.

Code Implementation

class Solution:
    def lengthLongestPath(self, input: str) -> int:
        maxlen = 0
        pathlen = {0: 0}
        for line in input.split('\n'):
            name = line.lstrip('\t')
            depth = len(line) - len(name)
            if '.' in name:
                maxlen = max(maxlen, pathlen[depth] + len(name))
            else:
                pathlen[depth + 1] = pathlen[depth] + len(name) + 1
        return maxlen
      
class Solution {
public:
    int lengthLongestPath(string input) {
        unordered_map<int, int> pathlen;
        pathlen[0] = 0;
        int maxlen = 0;
        int i = 0, n = input.size();
        while (i < n) {
            int depth = 0;
            while (i < n && input[i] == '\t') {
                ++depth;
                ++i;
            }
            int start = i;
            bool isFile = false;
            while (i < n && input[i] != '\n') {
                if (input[i] == '.') isFile = true;
                ++i;
            }
            string name = input.substr(start, i - start);
            if (isFile) {
                maxlen = max(maxlen, pathlen[depth] + (int)name.length());
            } else {
                pathlen[depth + 1] = pathlen[depth] + (int)name.length() + 1;
            }
            ++i; // skip '\n'
        }
        return maxlen;
    }
};
      
class Solution {
    public int lengthLongestPath(String input) {
        Map<Integer, Integer> pathlen = new HashMap<>();
        pathlen.put(0, 0);
        int maxlen = 0;
        for (String line : input.split("\n")) {
            String name = line.replaceFirst("^\t*", "");
            int depth = line.length() - name.length();
            if (name.contains(".")) {
                maxlen = Math.max(maxlen, pathlen.get(depth) + name.length());
            } else {
                pathlen.put(depth + 1, pathlen.get(depth) + name.length() + 1);
            }
        }
        return maxlen;
    }
}
      
var lengthLongestPath = function(input) {
    let maxlen = 0;
    let pathlen = {0: 0};
    let lines = input.split('\n');
    for (let line of lines) {
        let name = line.replace(/^\t+/, "");
        let depth = line.length - name.length;
        if (name.includes('.')) {
            maxlen = Math.max(maxlen, pathlen[depth] + name.length);
        } else {
            pathlen[depth + 1] = pathlen[depth] + name.length + 1;
        }
    }
    return maxlen;
};