📜  简化目录路径(类Unix)

📅  最后修改于: 2022-05-13 01:57:06.360000             🧑  作者: Mango

简化目录路径(类Unix)

给定文件的绝对路径(Unix 风格),简化它。请注意,绝对路径始终以“/”(根目录)开头,路径中的点代表当前目录,双点代表父目录。
例子:

"/a/./"   --> means stay at the current directory 'a'
"/a/b/.." --> means jump to the parent directory
              from 'b' to 'a'
"////"    --> consecutive multiple '/' are a  valid  
              path, they are equivalent to single "/".

Input : /home/
Output : /home

Input : /a/./b/../../c/
Output : /c

Input : /a/..
Output:/

Input : /a/../
Output : /

Input : /../../../../../a
Output : /a

Input : /a/./b/./c/./d/
Output : /a/b/c/d

Input : /a/../.././../../.
Output:/

Input : /a//b//c//////d
Output : /a/b/c/d

注意:给定的输入将始终具有有效的绝对路径。

方法一:
通过查看示例,我们可以看到上述简化过程的行为就像一个堆栈。每当我们遇到任何文件名时,我们只需将其压入堆栈即可。当我们遇到“。 “我们什么都不做。当我们在路径中找到“..”时,我们只需弹出最顶层的元素,因为我们必须跳回父目录。
当我们看到多个“////”时,我们会忽略它们,因为它们等同于一个“/”。在遍历整个字符串之后,堆栈中剩余的元素就是我们简化的绝对路径。我们必须创建另一个堆栈来反转存储在原始堆栈中的元素,然后将结果存储在字符串中。

C++
/* C++ program to simplify a Unix
   styled absolute path of a file */
#include 
using namespace std;
 
// function to simplify a Unix - styled
// absolute path
string simplify(string A)
{
    // stack to store the file's names.
    stack st;
 
    // temporary string which stores the extracted
    // directory name or commands("." / "..")
    // Eg. "/a/b/../."
    // dir will contain "a", "b", "..", ".";
    string dir;
 
    // contains resultant simplifies string.
    string res;
 
    // every string starts from root directory.
    res.append("/");
 
    // stores length of input string.
    int len_A = A.length();
 
    for (int i = 0; i < len_A; i++) {
 
        // we will clear the temporary string
        // every time to accommodate new directory
        // name or command.
        dir.clear();
 
        // skip all the multiple '/' Eg. "/////""
        while (A[i] == '/')
            i++;
 
        // stores directory's name("a", "b" etc.)
        // or commands("."/"..") into dir
        while (i < len_A && A[i] != '/') {
            dir.push_back(A[i]);
            i++;
        }
 
        // if dir has ".." just pop the topmost
        // element if the stack is not empty
        // otherwise ignore.
        if (dir.compare("..") == 0) {
            if (!st.empty())
                st.pop();           
        }
 
        // if dir has "." then simply continue
        // with the process.
        else if (dir.compare(".") == 0)
            continue;
         
        // pushes if it encounters directory's
        // name("a", "b").
        else if (dir.length() != 0)
            st.push(dir);       
    }
 
    // a temporary stack  (st1) which will contain
    // the reverse of original stack(st).
    stack st1;
    while (!st.empty()) {
        st1.push(st.top());
        st.pop();
    }
 
    // the st1 will contain the actual res.
    while (!st1.empty()) {
        string temp = st1.top();
         
        // if it's the last element no need
        // to append "/"
        if (st1.size() != 1)
            res.append(temp + "/");
        else
            res.append(temp);
 
        st1.pop();
    }
 
    return res;
}
 
// Driver code.
int main()
{
    // absolute path which we have to simplify.
    string str("/a/./b/../../c/");
    string res = simplify(str);
    cout << res;
    return 0;
}


Java
/* Java program to simplify a Unix
styled absolute path of a file */
import java.io.*;
import java.util.*;
 
class GFG
{
    public static void main(String []args)
    {
        // absolute path which we have to simplify.
        String str = new String("/a/./b/../../c/");
        String res = simplify(str);
        System.out.println(res);
    }
 
    // function to simplify a Unix - styled
    // absolute path
    static String simplify(String A)
    {
        // Stack to store the file's names.
        Stack st = new Stack();
 
        // temporary String which stores the extracted
        // directory name or commands("." / "..")
        // Eg. "/a/b/../."
         
        // contains resultant simplifies String.
        String res = "";
 
        // every String starts from root directory.
        res += "/";
 
        // stores length of input String.
        int len_A = A.length();
 
        for (int i = 0; i < len_A; i++)
        {
 
            // we will clear the temporary String
            // every time to accommodate new directory
            // name or command.
            // dir will contain "a", "b", "..", ".";
            String dir = "";
 
            // skip all the multiple '/' Eg. "/////""
            while (i < len_A && A.charAt(i) == '/')
                i++;
 
            // stores directory's name("a", "b" etc.)
            // or commands("."/"..") into dir
            while (i < len_A && A.charAt(i) != '/')
            {
                dir += A.charAt(i);
                i++;
            }
 
            // if dir has ".." just pop the topmost
            // element if the Stack is not empty
            // otherwise ignore.
            if (dir.equals("..") == true)
            {
                if (!st.empty())
                    st.pop();    
            }
 
            // if dir has "." then simply continue
            // with the process.
            else if (dir.equals(".") == true)
                continue;
             
            // pushes if it encounters directory's
            // name("a", "b").
            else if (dir.length() != 0)
                st.push(dir);
        }
 
        // a temporary Stack (st1) which will contain
        // the reverse of original Stack(st).
        Stack st1 = new Stack();
        while (!st.empty())
        {
             
            st1.push(st.pop());
            // st.pop();
        }
         
 
        // the st1 will contain the actual res.
        while (!st1.empty())
        {
             
            // if it's the last element no need
            // to append "/"
            if (st1.size() != 1)
                res += (st1.pop() + "/");
            else
                res += st1.pop();
 
            // st1.pop();
        }
        return res;
    }
 
}
 
// This code is contributed by ankush_953


Python3
# Python program to simplify a Unix
# styled absolute path of a file
 
# function to simplify a Unix - styled
# absolute path
 
 
def simplify(A):
    # stack to store the file's names.
    st = []
 
    # temporary string which stores the extracted
    # directory name or commands("." / "..")
    # Eg. "/a/b/../."
    # dir will contain "a", "b", "..", ".";
    dir = ""
 
    # contains resultant simplifies string.
    res = ""
 
    # every string starts from root directory.
    res += "/"
 
    # stores length of input string.
    len_A = len(A)
    i = 0
    while i < len_A:
 
        # we will clear the temporary string
        # every time to accommodate new directory
        # name or command.
        dir_str = ""
 
        # skip all the multiple '/' Eg. "##/""
        while (i < len_A and A[i] == '/'):
            i += 1
 
        # stores directory's name("a", "b" etc.)
        # or commands("."/"..") into dir
        while (i < len_A and A[i] != '/'):
            dir_str += A[i]
            i += 1
 
        # if dir has ".." just pop the topmost
        # element if the stack is not empty
        # otherwise ignore.
        if dir_str == "..":
            if len(st):
                st.pop()
 
        # if dir has "." then simply continue
        # with the process.
        elif dir_str == '.':
            continue
 
        # pushes if it encounters directory's
        # name("a", "b").
        elif len(dir_str) > 0:
            st.append(dir_str)
 
        i += 1
 
    # a temporary stack (st1) which will contain
    # the reverse of original stack(st).
    st1 = []
    while len(st):
        st1.append(st[-1])
        st.pop()
 
    # the st1 will contain the actual res.
    while len(st1):
        temp = st1[-1]
 
        # if it's the last element no need
        # to append "/"
        if (len(st1) != 1):
            res += (temp + "/")
        else:
            res += temp
        st1.pop()
 
    return res
 
 
# Driver code.
 
# absolute path which we have to simplify.
string = "/a/./b/../../c/"
res = simplify(string)
print(res)
 
# This code is contributed by ankush_953


C#
// C# program to simplify a Unix
// styled absolute path of a file
using System;
using System.Collections.Generic;
 
class GFG
{
    public static void Main(String []args)
    {
        // absolute path which we have to simplify.
        String str = ("/a/./b/../../c/");
        String res = simplify(str);
        Console.WriteLine(res);
    }
 
    // function to simplify a Unix - styled
    // absolute path
    static String simplify(String A)
    {
        // Stack to store the file's names.
        Stack st = new Stack();
 
        // temporary String which stores the extracted
        // directory name or commands("." / "..")
        // Eg. "/a/b/../."
         
        // contains resultant simplifies String.
        String res = "";
 
        // every String starts from root directory.
        res += "/";
 
        // stores length of input String.
        int len_A = A.Length;
 
        for (int i = 0; i < len_A; i++)
        {
 
            // we will clear the temporary String
            // every time to accommodate new directory
            // name or command.
            // dir will contain "a", "b", "..", ".";
            String dir = "";
 
            // skip all the multiple '/' Eg. "/////""
            while (i < len_A && A[i] == '/')
                i++;
 
            // stores directory's name("a", "b" etc.)
            // or commands("."/"..") into dir
            while (i < len_A && A[i] != '/')
            {
                dir += A[i];
                i++;
            }
 
            // if dir has ".." just pop the topmost
            // element if the Stack is not empty
            // otherwise ignore.
            if (dir.Equals("..") == true)
            {
                if (st.Count!=0)
                    st.Pop();    
            }
 
            // if dir has "." then simply continue
            // with the process.
            else if (dir.Equals(".") == true)
                continue;
             
            // pushes if it encounters directory's
            // name("a", "b").
            else if (dir.Length != 0)
                st.Push(dir);
        }
 
        // a temporary Stack (st1) which will contain
        // the reverse of original Stack(st).
        Stack st1 = new Stack();
        while (st.Count!=0)
        {
             
            st1.Push(st.Pop());
            // st.pop();
        }
         
 
        // the st1 will contain the actual res.
        while (st1.Count!=0)
        {
             
            // if it's the last element no need
            // to append "/"
            if (st1.Count!= 1)
                res += (st1.Pop() + "/");
            else
                res += st1.Pop();
 
            // st1.pop();
        }
        return res;
    }
}
 
// This code is contributed by Rajput-Ji


Javascript


C++
// C++ implementation of optimized Approach 1
#include 
using namespace std;
 
// function to simplify a Unix - styled
// absolute path
string simplify(string path)
{
    // using vector in place of stack
    vector v;
    int n = path.length();
    string ans;
    for (int i = 0; i < n; i++) {
        string dir = "";
        // forming the current directory.
        while (i < n && path[i] != '/') {
            dir += path[i];
            i++;
        }
 
        // if ".." , we pop.
        if (dir == "..") {
            if (!v.empty())
                v.pop_back();
        }
        else if (dir == "." || dir == "") {
            // do nothing (added for better understanding.)
        }
        else {
            // push the current directory into the vector.
            v.push_back(dir);
        }
    }
 
    // forming the ans
    for (auto i : v) {
        ans += "/" + i;
    }
 
    // vector is empty
    if (ans == "")
        return "/";
 
    return ans;
}
 
// Driver Code
int main()
{
    // absolute path which we have to simplify.
    string str("/a/./b/../../c/");
    string res = simplify(str);
    cout << res;
    return 0;
}
 
// This code is contributed by yashbeersingh42


Java
// Java implementation of optimized Approach 1
import java.util.*;
public class Main
{
    // function to simplify a Unix - styled
    // absolute path
    static String simplify(String path)
    {
        
        // using vector in place of stack
        Vector v = new Vector();
        int n = path.length();
        String ans = "";
        for (int i = 0; i < n; i++) {
            String dir = "";
            
            // forming the current directory.
            while (i < n && path.charAt(i) != '/') {
                dir += path.charAt(i);
                i++;
            }
       
            // if ".." , we pop.
            if (dir.equals("..")) {
                if (v.size() != 0)
                {
                    v.remove(v.size() - 1);
                }
            }
            else if (dir.equals(".") || dir.equals("")) {
                // do nothing (added for better understanding.)
            }
            else {
                // push the current directory into the vector.
                v.add(dir);
            }
        }
       
        // forming the ans
        for(String i : v) {
            ans += "/" + i;
        }
       
        // vector is empty
        if (ans == "")
            return "/";
       
        return ans;
    }
     
    public static void main(String[] args) {
        // absolute path which we have to simplify.
        String str = "/a/./b/../../c/";
        String res = simplify(str);
        System.out.print(res);
    }
}
 
// This code is contributed by decode2207.


Python3
# Python3 implementation of optimized Approach 1
 
# function to simplify a Unix - styled
# absolute path
def simplify(path):
   
    # using vector in place of stack
    v = []
    n = len(path)
    ans = ""
    for i in range(n):
        Dir = ""
         
        # forming the current directory.
        while (i < n and path[i] != '/'):
            Dir += path[i]
            i+=1
  
        # if ".." , we pop.
        if (Dir == "..") :
            if (len(v) > 0):
                v.pop()
        elif (Dir == "." or Dir == ""):
            # do nothing (added for better understanding.)
            continue
        else:
            # push the current directory into the vector.
            v.append(Dir)
  
    # forming the ans
    for i in v:
        ans += "/" + i
  
    # vector is empty
    if (ans == ""):
        return "/"
  
    return ans
 
# absolute path which we have to simplify.
Str = "/a/./b/../../c/"
res = simplify(Str)
print(res)
 
# This code is contributed by rameshtravel07


C#
// C# implementation of optimized Approach 1
using System;
using System.Collections.Generic;
class GFG {
     
    // function to simplify a Unix - styled
    // absolute path
    static string simplify(string path)
    {
       
        // using vector in place of stack
        List v = new List();
        int n = path.Length;
        string ans = "";
        for (int i = 0; i < n; i++) {
            string dir = "";
           
            // forming the current directory.
            while (i < n && path[i] != '/') {
                dir += path[i];
                i++;
            }
      
            // if ".." , we pop.
            if (dir == "..") {
                if (v.Count != 0)
                    v.RemoveAt(v.Count - 1);
            }
            else if (dir == "." || dir == "") {
                // do nothing (added for better understanding.)
            }
            else {
                // push the current directory into the vector.
                v.Add(dir);
            }
        }
      
        // forming the ans
        foreach(string i in v) {
            ans += "/" + i;
        }
      
        // vector is empty
        if (ans == "")
            return "/";
      
        return ans;
    }
 
  static void Main()
  {
     
    // absolute path which we have to simplify.
    string str = "/a/./b/../../c/";
    string res = simplify(str);
    Console.Write(res);
  }
}
 
// This code is contributed by divyeshrabadiya07.


Javascript


输出
/c

时间复杂度O(字符串长度)。

方法二:

  1. 在方法 1 中,如此形成的目录首先被压入堆栈,然后将堆栈反转以形成规范路径。
  2. 这里唯一的优化是减少堆栈操作的数量,这可以通过使用向量代替堆栈来完成。
  3. 推送和弹出操作可以分别使用push_back()pop_back()函数在向量中完成,并且可以通过简单地从左到右遍历向量来生成规范路径。

下面是使用向量的方法 1 的实现。

C++

// C++ implementation of optimized Approach 1
#include 
using namespace std;
 
// function to simplify a Unix - styled
// absolute path
string simplify(string path)
{
    // using vector in place of stack
    vector v;
    int n = path.length();
    string ans;
    for (int i = 0; i < n; i++) {
        string dir = "";
        // forming the current directory.
        while (i < n && path[i] != '/') {
            dir += path[i];
            i++;
        }
 
        // if ".." , we pop.
        if (dir == "..") {
            if (!v.empty())
                v.pop_back();
        }
        else if (dir == "." || dir == "") {
            // do nothing (added for better understanding.)
        }
        else {
            // push the current directory into the vector.
            v.push_back(dir);
        }
    }
 
    // forming the ans
    for (auto i : v) {
        ans += "/" + i;
    }
 
    // vector is empty
    if (ans == "")
        return "/";
 
    return ans;
}
 
// Driver Code
int main()
{
    // absolute path which we have to simplify.
    string str("/a/./b/../../c/");
    string res = simplify(str);
    cout << res;
    return 0;
}
 
// This code is contributed by yashbeersingh42

Java

// Java implementation of optimized Approach 1
import java.util.*;
public class Main
{
    // function to simplify a Unix - styled
    // absolute path
    static String simplify(String path)
    {
        
        // using vector in place of stack
        Vector v = new Vector();
        int n = path.length();
        String ans = "";
        for (int i = 0; i < n; i++) {
            String dir = "";
            
            // forming the current directory.
            while (i < n && path.charAt(i) != '/') {
                dir += path.charAt(i);
                i++;
            }
       
            // if ".." , we pop.
            if (dir.equals("..")) {
                if (v.size() != 0)
                {
                    v.remove(v.size() - 1);
                }
            }
            else if (dir.equals(".") || dir.equals("")) {
                // do nothing (added for better understanding.)
            }
            else {
                // push the current directory into the vector.
                v.add(dir);
            }
        }
       
        // forming the ans
        for(String i : v) {
            ans += "/" + i;
        }
       
        // vector is empty
        if (ans == "")
            return "/";
       
        return ans;
    }
     
    public static void main(String[] args) {
        // absolute path which we have to simplify.
        String str = "/a/./b/../../c/";
        String res = simplify(str);
        System.out.print(res);
    }
}
 
// This code is contributed by decode2207.

Python3

# Python3 implementation of optimized Approach 1
 
# function to simplify a Unix - styled
# absolute path
def simplify(path):
   
    # using vector in place of stack
    v = []
    n = len(path)
    ans = ""
    for i in range(n):
        Dir = ""
         
        # forming the current directory.
        while (i < n and path[i] != '/'):
            Dir += path[i]
            i+=1
  
        # if ".." , we pop.
        if (Dir == "..") :
            if (len(v) > 0):
                v.pop()
        elif (Dir == "." or Dir == ""):
            # do nothing (added for better understanding.)
            continue
        else:
            # push the current directory into the vector.
            v.append(Dir)
  
    # forming the ans
    for i in v:
        ans += "/" + i
  
    # vector is empty
    if (ans == ""):
        return "/"
  
    return ans
 
# absolute path which we have to simplify.
Str = "/a/./b/../../c/"
res = simplify(Str)
print(res)
 
# This code is contributed by rameshtravel07

C#

// C# implementation of optimized Approach 1
using System;
using System.Collections.Generic;
class GFG {
     
    // function to simplify a Unix - styled
    // absolute path
    static string simplify(string path)
    {
       
        // using vector in place of stack
        List v = new List();
        int n = path.Length;
        string ans = "";
        for (int i = 0; i < n; i++) {
            string dir = "";
           
            // forming the current directory.
            while (i < n && path[i] != '/') {
                dir += path[i];
                i++;
            }
      
            // if ".." , we pop.
            if (dir == "..") {
                if (v.Count != 0)
                    v.RemoveAt(v.Count - 1);
            }
            else if (dir == "." || dir == "") {
                // do nothing (added for better understanding.)
            }
            else {
                // push the current directory into the vector.
                v.Add(dir);
            }
        }
      
        // forming the ans
        foreach(string i in v) {
            ans += "/" + i;
        }
      
        // vector is empty
        if (ans == "")
            return "/";
      
        return ans;
    }
 
  static void Main()
  {
     
    // absolute path which we have to simplify.
    string str = "/a/./b/../../c/";
    string res = simplify(str);
    Console.Write(res);
  }
}
 
// This code is contributed by divyeshrabadiya07.

Javascript


输出
/c


时间复杂度: O(字符串长度)。