【LeetCode-字符串】简化路径

题目描述

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

示例:

输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。

输入:"/a/./b/../../c/"
输出:"/c"

输入:"/a//b////c/d//././/.."
输出:"/a/b/c"

题目链接: https://leetcode-cn.com/problems/simplify-path/

思路1

第一想法是用栈来做,假设每个目录都以/分隔,首先根据/分割字符串,可以得到一系列目录,遍历目录,如果当前目录为.,则不做操作;如果当前目录为..并且栈不空,则将栈顶元素弹出;否则就将当前目录入栈。然后将栈中的元素弹出,以/分隔作为答案。但使用栈有一个问题,举个例子,假设输入为/a/b/c,则栈的情况为栈底|a|b|c|栈顶,所以c先弹出,a最后弹出,最终的结果是/c/b/a,这是不对的,原因是在输出时我们应该从栈底开始出栈,这种情况下可以使用双端队列 deque 来实现。

代码如下:

class Solution {
public:
    string simplifyPath(string path) {
        if(path.empty()) return path;
        if(path.size()==1) return "/";

        if(path.back()=='/') path.pop_back();
        deque<string> st;  // 使用双端队列而不是栈
        int i = 1;
        int j = 1;
        while(j<path.size()){  // 使用两个指针来分割字符串
            if(path[j]!='/') j++;
            else{
                string ss = path.substr(i, j-i);  // ss表示当前目录
                if(ss==".."){  // ".."表示出队列
                    if(!st.empty()) st.pop_back();
                }
                else if(!ss.empty()){ // 如果ss非空
                    if(ss.size()>1) st.push_back(ss); //长度大于1说明不是'.',入队列
                    else if(ss[0]!='.') st.push_back(ss); //第一个字符串为'.'也可以入队列,例如".ssh"
                }
                while(j<path.size() && path[j]=='/') j++; // 跳过多个'/'的情况,例如"/a/////b/c"
                i = j;
            }
        }
        string ss = path.substr(i, j-i);  /*提取最后一个目录,入队列的逻辑和上面是一样的*/
        if(ss==".."){
            if(!st.empty()) st.pop_back();
        }
        else if(!ss.empty()){
            if(ss.size()>1) st.push_back(ss);
            else if(ss[0]!='.') st.push_back(ss);
        }

        if(st.empty()) return "/";  // 别忘了这一句

        string ans = "";
        while(!st.empty()){
            string s = st.front(); st.pop_front();  // 从队头出队列
            ans += "/" + s;
        }
        return ans;
    }
};
  • 时间复杂度:O(n)
    n 为 path 的长度。
  • 空间复制度:O(n)

思路2

思路 1 使用双指针来对输入的路径进行分割,可以直接使用 c++ 自带的 istringstreamgetline 组合来分割字符串,具体代码如下:

class Solution {
public:
    string simplifyPath(string path) {
        if(path.empty()) return path;
        if(path.size()==1) return "/";

        deque<string> q;
        istringstream iss(path);
        string dir = "";
        while(getline(iss, dir, '/')){
            if(!dir.empty() && dir!="." && dir!=".."){
                q.push_back(dir);
            }else if(!q.empty() && dir==".."){
                q.pop_back();
            }
        }
        if(q.empty()) return "/";
        string ans = "";
        while(!q.empty()){
            string s = q.front(); q.pop_front();
            ans += "/" + s;
        }
        return ans;
    }
};

这样代码更加简洁。

参考

思路 2 参考了 https://leetcode-cn.com/problems/simplify-path/comments/69661

上一篇:nginx-http之empty_gif(五)


下一篇:4.模拟队列