Leetcode0388. The longest absolute path to a file (medium, stack, DFS)

content

1. Problem description

2. Problem solving analysis

3. Code implementation


1. Problem description

Suppose there is a filesystem that stores both files and directories. The following figure shows an example of a file system:

This will be  dir the only directory in the root directory. dir Contains two subdirectories  subdir1 and  subdir2 . subdir1 Include files  file1.ext and subdirectories  subsubdir1; subdir2 include subdirectories  subsubdir2, which contain files  file2.ext .

In text format, it looks like this (⟶ indicates a tab):

dir
⟶ subdir1
⟶ ⟶ file1.ext
⟶ ⟶ subsubdir1
⟶ subdir2
⟶ ⟶ subsubdir2
⟶ ⟶ ⟶ file2.ext

If represented by code, the filesystem above can be written as  "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext" . '\n' and  '\t' are newline and tab respectively.

Every file and folder in the filesystem has a unique  absolute path  , the order of directories that must be opened to reach where the file/directory is located, all paths are  '/' concatenated with. In the above example,  file2.ext the  absolute path pointed to  is  "dir/subdir2/subsubdir2/file2.ext" . Each directory name consists of letters, numbers, and/or spaces, and the format that each filename follows  name.extension , where  name sum  extensionconsists of letters, numbers, and/or spaces.

Given a string representing a filesystem in the above format  input , return   the length  of the  longest absolute path to  a file in the filesystem  . Returns if there are no files in the system  0.

Example 1:

Input: input = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
 Output: 20
 Explanation: There is only one file, the absolute path is "dir/subdir2/file.ext", and the path length is 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: Two files exist: 
"dir/subdir1/file1.ext" , path length 21 
"dir/subdir2/subsubdir2/file2.ext" , path length 32 
returns 32 because this is the longest path

Example 3:

Input: input = "a"
 Output: 0
 Explanation: No file exists

Example 4:

Input: input = "file1.txt\nfile2.txt\nlongfile.txt"
 Output: 12
 Explanation: There are 3 files in the root directory. 
Because the absolute path to anything in the root directory is just the name itself, the answer is "longfile.txt" with a path length of 12

hint:

  • 1 <= input.length <= 10^4
  • input May contain lowercase or uppercase English letters, a newline  '\n', a tab  '\t', a dot  '.', a space  ' ', and numbers.

Source: LeetCode
Link: https://leetcode-cn.com/problems/longest-absolute-file-path The
copyright belongs to Leetcode.com. For commercial reprints, please contact the official authorization, and for non-commercial reprints, please indicate the source.

2. Problem solving analysis

        The most intuitive way is to construct the directory tree explicitly, except the root node, each directory or leaf node stores its own string length, and the value of the root node is 0. Then traverse the tree to find the total path length of each leaf (file): the sum of the values ​​from the root node to its own nodes.

        Is it possible to skip the process of building the tree explicitly?

        As shown in the diagram of Example 2, all subdirectories or files of subdir1 must appear before subdir2, which is at the same level as it. In the same directory, are the files necessarily arranged in front of the subdirectories? This is not clearly stated in the problem description, and this assumption is not made for the time being .

        This is actually an expansion of a preorder traversal of a directory tree, which can be solved in a manner similar to depth-first traversal.

        A stack is used to maintain the information of the directory tree. First, the root directory information is pushed onto the stack, which contains the absolute path length of 0 and its depth of 0. The text format of the directory tree represents scanning from left to right, and the following two cases of files and directories are considered separately:

  • (1) If a file is encountered (judged by whether there is an extension separated by "."), it will not be pushed onto the stack. Check the depth of the top node of the stack (if there is a peek function, you can use the peek method to query the stack top information without popping the top of the stack; if there is no peek function, you can pop it first and then put it back), if it is not greater than the depth of the current file, pop it off the stack. Repeat until the first element with greater depth. Add its absolute path length to its own file name length to get its corresponding absolute path length, compare it with the current maximum path length and update the maximum path length.
  • (2) When encountering a directory, query the elements in the stack. If the depth of the top element of the stack is not greater than the depth of the current directory, pop it up; repeat until the first element with a larger depth is found, and calculate based on the absolute path length of this element The absolute path length of the current directory, push the information of the current directory onto the stack
  • (3) Repeat (1), (2) search process until the end

When calculating the absolute path length of a directory, in addition to the root directory, the location occupied by a "/" after it should be considered.

Taking Example 1 as an example, the processing steps are as follows:

  • (1) The root directory is pushed into the stack, and its information is (0,0), the former represents the absolute path length, and the latter represents the depth
  • (2) dir is pushed onto the stack, and its information is (4,1). The length of dir itself is 3, plus the length of "/" becomes 4, so the absolute path length is 4
  • (3) subdir1 is pushed into the stack, and its information is (12,2)
  • (4) subdir2. Since the depth of subdir2 is the same as that of subdir1 at the top of the stack at this time, pop subdir1 and push subdir2 onto the stack, and its information is (12,2)
  • (5) file.txt, its own length is 8, the current stack top element length is 12, so its absolute path length is 20

        The remaining details are how to identify the directory and file names and the depth of the directory from the input string.

        (1) Identification with \n as the end of a valid name. In order to facilitate the processing of the last name, first append a \n to the input tail

        (2) The following code actually implements a finite state machine when searching for a name and its depth, although it is not explicitly written in the form of a state machine 

        

3. Code implementation

import time
from typing import List
from collections import deque

class Solution:
    def lengthLongestPath(self, input: str) -> int:
        
        input = input +'\n' # Attach one '\n' for the convenience of processing
        maxlen = 0
        q = deque([(0,0)]) # Put root node into stack

        tab_cnt = 0       
        name    = ''
        isFile  = False
        for k,c in enumerate(input):
            if c=='\t':
                tab_cnt += 1
            elif c=='\n':
                # Found a new name, either a dir name or a file name
                if isFile:
                    # A file
                    # print('A file is found: ',name)
                    while True:
                        length, layer = q.pop()
                        if layer < (tab_cnt+1):
                            filePathLen = len(name) + length
                            maxlen = filePathLen if filePathLen>maxlen else maxlen
                            q.append((length, layer)) # Put it back into stack
                            break
                else:
                    # A dir
                    # print('A dir is found: ',name)
                    while True:
                        length, layer = q.pop()
                        if layer < (tab_cnt+1):
                            dirPathLen = len(name) + length + 1
                            q.append((length, layer)) # Put it back into stack
                            q.append((dirPathLen,tab_cnt+1))
                            break
                # Reset 
                tab_cnt = 0
                name    = ''
                isFile  = False
            else:
                name = name + c
                if c=='.':
                    isFile = True
            
        return maxlen
                
if __name__ == "__main__":
    
    sln = Solution()
    input = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
    print(sln.lengthLongestPath(input))
    
    input = "dir\n\tsubdir1\n\t\tfile.ext\n\tsubdir2\n\t\tfile.ext"
    print(sln.lengthLongestPath(input))
    
    input = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
    print(sln.lengthLongestPath(input))

    input = "dir\n\tsubdir1\n\t\tsubsubdir1\n\t\tfile1.ext\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
    print(sln.lengthLongestPath(input))
    
    input = "a"
    print(sln.lengthLongestPath(input))
    
    input = "file1.txt\nfile2.txt\nlongfile.txt"
    print(sln.lengthLongestPath(input))

        Execution time: 40 ms, beat 37.35% of users in all Python3 commits

        Memory consumption: 15.1 MB, beating 27.24% of users across all Python3 commits

        This problem is not the kind of solution that can be seen at a glance, so it takes a lot of time to think about the solution itself, but once you think about it clearly, the code is passed in one go from submission to submission. Although the performance is not very good, I still feel a little small Proud ^-^.

        I glanced at the official solution, and it felt more complicated than I thought, so I didn't have the patience to read it.

        Back to the main directory: Leetcode daily problem-solving notes (dynamic update...)

Guess you like

Origin blog.csdn.net/chenxy_bwave/article/details/124287995