模拟目录管理

题目描述

实现一个模拟目录管理功能的软件, 输入一个命令序列, 输出最后一条命令运行结果.

支持命令:

  • 创建目录命令: mkdir 目录名称, 如 mkdir abc 为在当前目录创建abc目录, 如果已存在同名目录则不执行任何操作. 此命令无输出.
  • 进入目录命令: cd 目录名称, 如 cd abc 为进入abc目录, 特别地, cd .. 为返回上级目录, 如果目录不存在则不执行任何操作. 此命令无输出.
  • 查看当前所在路径命令: pwd, 输出当前路径字符串.

约束:

  • 目录名称仅支持小写字母
  • mkdir 和 cd 命令的参数仅支持单个目录, 如: mkdir abccd abc; 不支持嵌套路径和绝对路径, 如 mkdir abc/efg, cd abc/efg, mkdir /abc/efg, cd /abc/efg 是不支持的.
  • 目录符号为 /, 根目录/作为初始目录.
  • 任何不符合上述定义的无效命令不做任何处理并且无输出

输入描述

输入 N 行字符串, 每一行字符串是一条命令.

输出描述

输出最后一条命令运行结果字符串.

备注

命令行数限制100行以内, 目录名称限制10个字符以内.

用例1

输入:

mkdir abc
cd abc
pwd

输入:

/abc/

说明: 在根目录创建一个abc的目录并进入abc目录中查看当前目录路径, 输出当前路径 /abc/

题解

Python


import string
import sys

class FileNode:

    def __init__(self, path, parent=None):
        # 当前目录的绝对路径
        self.path = path
        # 指向父目录节点
        self.parent = parent

        # 子目录节点, 默认为空
        self.children = {}

        # 创建特属的子节点, 指向父目录
        if self.parent:
            self.children[".."] = self.parent

    def validate_folder_name(self, folder_name) -> bool:
        # 检查目录名是否包含无效字符
        for char in folder_name:
            if char not in string.ascii_lowercase:
                return False
        return True

    def mkdir(self, folder_name):
        if not self.validate_folder_name(folder_name):
            return False

        # 检查相同的目录名是否已经存在
        if folder_name in self.children:
            return False

        # 创建新的目录节点, 并存储到子目录中
        path = self.path + folder_name + "/"
        new_folder = FileNode(path, self)
        self.children[folder_name] = new_folder
        return True

    def cd(self, folder_name):
        # 进入到父目录
        if folder_name == "..":
            return True, self.parent

        # 校验目录名
        if not self.validate_folder_name(folder_name):
            return False, self

        # 未找到子目录
        if folder_name not in self.children:
            return False, self

        return True, self.children[folder_name]

def main():
    # 首先创建根目录
    root = FileNode("/")
    # 创建根目录的引用, 当前工作目录
    cwd = root

    # 然后依次读取输入, 如果输入无效, 则直接忽略, 并继续读取下一条输入
    for line in sys.stdin:
        line = line.strip()
        if not line:
            continue

        # 解析命令
        parts = line.split()
        cmd = parts[0]
        if cmd == "pwd":
            # 打印当前的目录
            if len(parts) == 1:
                print(cwd.path)
        elif cmd == "cd":
            if len(parts) == 2:
                # 切换工作目录
                folder_name = parts[1]
                ok, new_cwd = cwd.cd(folder_name)
                if not ok:
                    print("[cd] Invalid command:", line)
                else:
                    cwd = new_cwd
        elif cmd == "mkdir":
            # 创建子目录
            if len(parts) == 2:
                folder_name = parts[1]
                ok = cwd.mkdir(folder_name)
                if not ok:
                    print("[mkdir] Invalid command:", line)


if __name__ == "__main__":
    main()

Rust

use std::collections::{HashMap, HashSet};
use std::io::{stdin, BufRead};

/// 目录节点
pub struct FolderEntry {
    /// 当前目录的绝对路径
    path: String,
    /// 指向父节点
    parent: String,
    /// 子节点
    children: HashSet<String>,
}

pub type FolderMap = HashMap<String, FolderEntry>;

impl FolderEntry {
    #[must_use]
    #[inline]
    pub fn new(path: String, parent: String) -> Self {
        Self {
            path,
            parent,
            children: HashSet::new(),
        }
    }

    fn validate_folder_name(folder_name: &str) -> bool {
        for chr in folder_name.chars() {
            if !chr.is_ascii_lowercase() {
                return false;
            }
        }
        true
    }

    pub fn mkdir(&mut self, folder_name: String) -> Result<Self, String> {
        if !Self::validate_folder_name(&folder_name) {
            return Err(folder_name);
        }
        if self.children.contains(&folder_name) {
            return Err(folder_name);
        }

        let path = Self::to_path(&self.path, &folder_name);
        self.children.insert(folder_name);
        Ok(Self::new(path, self.path.clone()))
    }

    fn to_path(path: &str, folder_name: &str) -> String {
        format!("{path}{folder_name}/")
    }

    pub fn cd(&self, folder_name: &str) -> Option<String> {
        if folder_name == ".." {
            return Some(self.parent.clone());
        }
        if !Self::validate_folder_name(folder_name) {
            return None;
        }
        if self.children.contains(folder_name) {
            let path = Self::to_path(&self.path, folder_name);
            Some(path)
        } else {
            None
        }
    }
}

fn solution() {
    let root = FolderEntry::new("/".to_owned(), "/".to_owned());
    let mut map = HashMap::new();
    let mut cwd = root.path.clone();
    map.insert(root.path.clone(), root);

    for line in stdin().lock().lines() {
        let line = line.unwrap();
        let line = line.trim_ascii();
        if line.is_empty() {
            continue;
        }
        let mut parts = line.split_ascii_whitespace();
        match parts.next() {
            Some("pwd") => {
                if parts.next().is_none() {
                    println!("pwd: {}", cwd);
                }
            }
            Some("cd") => {
                // 切换工作目录
                if let Some(folder_name) = parts.next() {
                    if parts.next().is_some() {
                        continue;
                    }
                    if let Some(cwd_entry) = map.get_mut(&cwd) {
                        if let Some(new_folder_name) = cwd_entry.cd(folder_name) {
                            cwd = new_folder_name;
                        }
                    }
                }
            }
            Some("mkdir") => {
                // 创建子目录
                if let Some(folder_name) = parts.next() {
                    if parts.next().is_some() {
                        continue;
                    }
                    if let Some(cwd_entry) = map.get_mut(&cwd) {
                        if let Ok(new_folder) = cwd_entry.mkdir(folder_name.to_owned()) {
                            map.insert(new_folder.path.clone(), new_folder);
                        }
                    }
                }
            }
            Some(_) | None => {}
        }
    }
}

fn main() {
    solution()
}