题目:
Given an absolute path for a file (Unix-style), simplify it. Or in other words, convert it to the canonical path.
In a UNIX-style file system, a period .
refers to the current directory. Furthermore, a double period ..
moves the directory up a level. For more information, see: Absolute path vs relative path in Linux/Unix
Note that the returned canonical path must always begin with a slash /
, and there must be only a single slash /
between two directory names. The last directory name (if it exists) must not end with a trailing /
. Also, the canonical path must be the shortest string representing the absolute path.
Example 1:
Input: "/home/"
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.
Example 2:
Input: "/../"
Output: "/"
Explanation: Going one level up from the root directory is a no-op, as the root level is the highest level you can go.
Example 3:
Input: "/home//foo/"
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one.
Example 4:
Input: "/a/./b/../../c/"
Output: "/c"
Example 5:
Input: "/a/../../b/../c//.//"
Output: "/c"
Example 6:
Input: "/a//bc/d//././/.."
Output: "/a/b/c"
题解:
这是一道简化路径的题,路径简化的依据是:
当遇到“/../"则需要返回上级目录,需检查上级目录是否为空。
当遇到"/./"则表示是本级目录,无需做任何特殊操作。
当遇到"//"则表示是本级目录,无需做任何操作。
当遇到其他字符则表示是文件夹名,无需简化。
当字符串是空或者遇到”/../”,则需要返回一个"/"。
当遇见"/a//b",则需要简化为"/a/b"。
根据这些要求,我需要两个栈来解决问题。
先将字符串依"/"分割出来,然后检查每个分割出来的字符串。
当字符串为空或者为".",不做任何操作。
当字符串不为"..",则将字符串入栈。
当字符串为"..", 则弹栈(返回上级目录)。
当对所有分割成的字符串都处理完后,检查第一个栈是否为空,如果栈为空,则证明没有可以重建的目录名,返回"/"即可。
当第一个栈不为空时,这时候我们需要还原path。但是不能弹出栈,因为按照要求栈底元素应该为最先还原的目录path。
例如:原始path是 /a/b/c/,栈里的顺序是:a b c,如果依次弹栈还原的话是:/c/b/a(错误!),正确答案为:/a/b/c
所以这里我利用Java中LinkedList 数据类型来表示第一个栈。LinkedList数据类型很强大,包含了栈和队列的实现。所以最后还原时调用removeLast()函数就可以解决顺序问题。
代码为:
import java.util.LinkedList;
public class SimplifyPath
{
public static void main(String[] args)
{
System.out.println(simplifyPath("/home/")); // /home
System.out.println(simplifyPath("/../")); // /
System.out.println(simplifyPath("/home//foo/")); // /home/foo
System.out.println(simplifyPath("/a/./b/../../c/")); // /c
System.out.println(simplifyPath("/a/../../b/../c//.//")); // /c
System.out.println(simplifyPath("/a//bc/d//././/..")); // /a/b/c
}
public static String simplifyPath(String path)
{
if (path == null || path.length() == 0)
{
return "/";
}
String[] splits = path.split("/");
LinkedList<String> linkedList = new LinkedList<String>();
for (String s : splits)
{
if (s.equals("") || s.equals("."))
{
continue;
}
else if (s.equals(".."))
{
if (!linkedList.isEmpty())
{
linkedList.removeFirst();
}
}
else
{
linkedList.addFirst(s);
}
}
StringBuffer sb = new StringBuffer();
if (linkedList.isEmpty())
{
linkedList.push("");
}
while (!linkedList.isEmpty())
{
sb.append("/").append(linkedList.removeLast());
}
return sb.toString();
}
}
这里注意:
判断字符串相等与否要用.equals(),因为是引用类型。
要注意split函数是可以split出空字符的,例如://b/ 会被split结果为["","b"]。
最后使用StringBuilder进行拼接,由于String在每次对字符串修改时候均会生成一个新的String,效率较低,一般会采用StringBuilder或者StringBuffer来进行字符串修改的操作,StringBuilder是StringBuffer的简易替换,是非线程安全的,而StringBuffer是线程安全的。