@(leetcode)[字符串|DFS|Google]
The string "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
represents:
dir
subdir1
subdir2
file.ext
a directory dir contains an empty sub-directories subdir1 and a sub-directory subdir2 containing a file file.ext.
The string "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
represents:
dir
subdir1
file1.ext
subsubdir1
subdir2
subsubdir2
file2.ext
a directory dir contains two sub-directories subdir1
and subdir2. subdir1
contains a file file1.extand an empty second-level sub-directory subsubdir1. subdir2
contains a second-level sub-directory subsubdir2 containing a file file2.ext
.
We are interested in finding the longest(number of characters) absolute path to a file within our file system. That is, for example, in the second example above, the longest absolute path is "dir/subdr2/subsubdir2/file.ext"
, and its length is 30
.
Given a string representing the file system in the above format, return the length of the longest absolute path to file in the abstracted file system. Simply put, that is the length of a valid path that ends with a file, and a file contains . and an extension.
Time complexity required: O(n)
where n is the size of the input string.
Notice that a/aa/aaa/file1.txt
is not the path you want, if there is aaaaaaaaaaaaaaaaaaaaa/sth.png
.
Solution
#include <iostream>
#include <stack>
#include <string>
#include <cassert>
using namespace std;
//更新最长路径, 当扫描遇到 '\n'的时候说明已经处理完当前 depth的一个文件夹/文件
void update(stack<int>& len_st, int& current_len, int& depth,
bool& is_file, int& res) {
//比较len_st的深度与当前深度的关系, 如果len_st保存的深度大,则pop栈顶元素直到与当前深度depth相同
while(len_st.size() > depth) {
len_st.pop();
}
//如果栈不为空, 取出栈顶元素,表示在到当前层之间的长度,然后加上当前层的长度
int len = ((len_st.empty()) ? 0 : len_st.top()) + current_len;
if(is_file && len > res) {
res = len;
}
len_st.push(len);
current_len = depth = 0;
is_file = false;
}
//其实这道题就是一个多叉树的深度遍历,并找到最深路径长度,转换成用字符串来表示,这样关键就是在于
//如果区分不同的层(递归深度),通过分析容易得出可以用\t的个数来表示目录深度。因此接下来就按照
//深度遍历的思路来搜索就可以了,算法的时间复杂度O(n) 空间复杂度O(n)
int get_longest_path(const string & path) {
if(path.empty()) {
return 0;
}
int res = 0, current_len = 0, depth = 0;
bool is_file = false;
//保存每层路径的长度,栈顶元素是当前搜索路径的长度
stack<int> len_st;
int str_len = path.size();
for(int i = 0; i < str_len; ++i) {
if(path[i] == '\n') {
update(len_st, current_len, depth, is_file, res);
} else if(path[i] == '\t') {
//每识别一个\t目录的深度就增加1
++depth;
} else {
if(path[i] == '.') {
is_file = true;
}
++current_len;
}
}
update(len_st, current_len, depth, is_file, res);
return res;
}
void test() {
{
string str = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext";
assert(18 == get_longest_path(str));
}
{
string str = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext";
assert(29 == get_longest_path(str));
}
{
string str = "a\n\tdir1\n\t\tdir2\n\t\t\tdir3\n\taaaaaaaaaaaaaaaaaaa.txt";
assert(24 == get_longest_path(str));
}
}
int main() {
test();
}