content
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 extension
consists 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...)