zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    Django错误笔记1
    Django学习笔记1 启动及配置一个Django项目
    ubuntu 安装mysqldb
    二叉树 总结
    序列二叉树和反序列 (不是自己做的)
    二叉树的路径
    二叉搜索树的后续遍历
    二叉树层序遍历
    栈的压入 弹出序列
    包含 min的栈
  • 原文地址:https://www.cnblogs.com/flix/p/13594736.html
Copyright © 2011-2022 走看看