71. Simplify Path(简化路径)
1. 题目描述
以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径
请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。
示例 1:
输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例 2:
输入:"/…/"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
示例 3:
输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:
输入:"/a/./b/…/…/c/"
输出:"/c"
示例 5:
输入:"/a/…/…/b/…/c//.//"
输出:"/c"
示例 6:
输入:"/a//b////c/d//././/…"
输出:"/a/b/c"
2. 分组处理(Process by Groups)
2.1 解题思路
笔者认为这道题从两个方面来整理总结比较合适:1)重点;2)难点。本题如果使用内置函数和额外空间,解题思路和代码比较简单不难,所以不存在太多的难点,重点就放在了几个函数的使用上面;另一方面,如果不适用任何内置函数和额外空间,那么本题在代码和思路上比较难了。所以本文先以重点入手,然后循循渐进讲解难点部分(下面"…“都为"两个点”,不知道为什么会显示成这样)。
首先我们先来明确一点简化路径的规则:
- 起始一定有一个’/’,两个文件夹之间有一个或多个’/’,路径最后有0~多个’/’,所以这里需要简化相邻两个文件夹只有一个’/’,末尾没有’/’,起始一个’/’;
- “/.” 或 “/./” 表示留在本级目录;"/…" 或 “/…/“表示返回上级目录;其余情况都表示文件夹名,比如”/…”(这里为三个点),"/.hidden";
所以根据上面的规则,我们可以把’/‘作为分隔符,两个’/'之间的内容作为一个分组(group),获取一个分组,我们按照上面的规则进行分情况处理:
- 如果 group == “” 或者 group == “.”,前者表示有多个连续’/’,后者表示"/.“或”/./",只需跳过继续处理即可;
- 如果 group == “…”,表示"/…“或”/…/"表示返回上级目录,如果前面有目录,则需要去掉;我们用一个数组存储分组的内容,如果数组长度不为0,则删除最后一个分组;
- 如果 group != “…”,则把group加入数组中;
以"/a/…/…/b/…/c//.//"为例,分组处理过程:
1)读取a:
| - | - |
|---|---|
| a | - |
2)读取第一个和第二个"…":
| - | - |
|---|---|
| - | - |
3)读取b:
| - | - |
|---|---|
| b | - |
4)读取第三个"…":
| - | - |
|---|---|
| - | - |
5)读取c:
| - | - |
|---|---|
| c | - |
6)读取".":
| - | - |
|---|---|
| c | - |
最后我们用’/'和每个数组的string进行拼接,如果答案string不为空,则返回答案string;反之,返回"/",表示根目录。所以整体的处理思路不难,重点介绍一下代码中遇到的两个内置函数:1)stringstream 和 2)getline;
(1)stringstream表示输入输出流,我们通过stringstream.str(const string& s)方法,把字符串s放到输入输出流中;
(2)istream& getline (istream& is, string& str, char delim)可以从输入流(istream)中读取数据,如果分隔符delim没有指定,则遇到换行符,停止读取,将之前读取的内容放在str中;如果delim被指定,则遇到指定的分隔符,停止读取,将之前读取的内容放在str中;或者当遇到文本末尾,也会自动停止读取。另外,分隔符不会被读取到str中;
到此,理解了解题思路和streastream,getline两个函数的用法,这道题的代码非常好理解,也容易写出来。此部分适用代码:2.2.1 使用内置函数和额外空间(推荐)
那么接下来我们来介绍一下不使用内置函数和额外空间的思路和方法:
因为我们不能使用额外空间,所以就不能像上面那样忽略所有’/’,等最后进行拼接了。那么,我们需要把’/‘加入到分组处理的思路之中。之前的思路不保留任何’/’,接下来的分组处理就需要保存一个’/’:
还是以上面的"/a/…/…/b/…/c//."为例,之前思路的角度:
| - | - | - | - | - | - | |
|---|---|---|---|---|---|---|
| a | … | … | b | … | c | . |
现在的角度:
| - | - | - | - | - | - | |
|---|---|---|---|---|---|---|
| /a | /… | /… | /b | /… | /c | /. |
所以我们以每组’/‘为起始信号,按照上面的规则进行处理。注意同样是遇到’/’,如果后面有其他内容,而不是连续’/’,所需要的操作是不一样的,所以我们初始化一个status来区别这两种情。我们也把其他情况分类到不同的status下面。
因为不使用额外空间,因而读取的数据需要写在原来的path中,所以初始化序号(idx) = 0,表示从序号0位置开始写入,也表示此时字符串为空。之后,我们根据每种情况进行写入和删除,删除操作只需要前移动idx,无需更改任何数据。下面举几个典型的例子来说明这个写入和删除操作:
例子1:"///…hi"

例子2:"/a/…"

本文详细解析了如何简化Unix风格的文件路径,遵循特定规则处理符号.和..,并提供两种解题思路:一种使用内置函数和额外空间,另一种不使用任何内置函数和额外空间。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



