百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

LeetCode 力扣官方题解 | 71. 简化路径

bigegpt 2024-08-07 17:37 3 浏览


题目描述

给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,'//')都被视为单个斜杠 '/' 。对于此问题,任何其他格式的点(例如,'...')均被视为文件/目录名称。

请注意,返回的 规范路径 必须遵循下述格式:

  • 始终以斜杠 '/' 开头。
  • 两个目录名之间必须只有一个斜杠 '/' 。
  • 最后一个目录名(如果存在)不能 以 '/' 结尾。
  • 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.' 或 '..')。

返回简化后得到的 规范路径

示例 1:

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

示例 2:

输入:path = "/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。

示例 3:

输入:path = "/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。

示例 4:

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

提示:

  • 1 <= path.length <= 3000
  • path 由英文字母,数字,'.','/' 或 '_' 组成。
  • path 是一个有效的 Unix 风格绝对路径。


解决方案

方法一:栈

我们首先将给定的字符串 path 根据 / 分割成一个由若干字符串组成的列表,记为 names。根据题目中规定的「规范路径的下述格式」,names 中包含的字符串只能为以下几种:

  • 空字符串。例如当出现多个连续的 /,就会分割出空字符串;
  • 一个点 .;
  • 两个点 ..;
  • 只包含英文字母、数字或 _ 的目录名。

对于「空字符串」以及「一个点」,我们实际上无需对它们进行处理,因为「空字符串」没有任何含义,而「一个点」表示当前目录本身,我们无需切换目录。

对于「两个点」或者「目录名」,我们则可以用一个栈来维护路径中的每一个目录名。当我们遇到「两个点」时,需要将目录切换到上一级,因此只要栈不为空,我们就弹出栈顶的目录。当我们遇到「目录名」时,就把它放入栈。

这样一来,我们只需要遍历 names 中的每个字符串并进行上述操作即可。在所有的操作完成后,我们将从栈底到栈顶的字符串用 / 进行连接,再在最前面加上 / 表示根目录,就可以得到简化后的规范路径。

代码

C++

class Solution {
public:
    string simplifyPath(string path) {
        auto split = [](const string& s, char delim) -> vector<string> {
            vector<string> ans;
            string cur;
            for (char ch: s) {
                if (ch == delim) {
                    ans.push_back(move(cur));
                    cur.clear();
                }
                else {
                    cur += ch;
                }
            }
            ans.push_back(move(cur));
            return ans;
        };

        vector<string> names = split(path, '/');
        vector<string> stack;
        for (string& name: names) {
            if (name == "..") {
                if (!stack.empty()) {
                    stack.pop_back();
                }
            }
            else if (!name.empty() && name != ".") {
                stack.push_back(move(name));
            }
        }
        string ans;
        if (stack.empty()) {
            ans = "/";
        }
        else {
            for (string& name: stack) {
                ans += "/" + move(name);
            }
        }
        return ans;
    }
};

Java

class Solution {
    public String simplifyPath(String path) {
        String[] names = path.split("/");
        Deque<String> stack = new ArrayDeque<String>();
        for (String name : names) {
            if ("..".equals(name)) {
                if (!stack.isEmpty()) {
                    stack.pollLast();
                }
            } else if (name.length() > 0 && !".".equals(name)) {
                stack.offerLast(name);
            }
        }
        StringBuffer ans = new StringBuffer();
        if (stack.isEmpty()) {
            ans.append('/');
        } else {
            while (!stack.isEmpty()) {
                ans.append('/');
                ans.append(stack.pollFirst());
            }
        }
        return ans.toString();
    }
}

C#

public class Solution {
    public string SimplifyPath(string path) {
        string[] names = path.Split("/");
        IList<string> stack = new List<string>();
        foreach (string name in names) {
            if ("..".Equals(name)) {
                if (stack.Count > 0) {
                    stack.RemoveAt(stack.Count - 1);
                }
            } else if (name.Length > 0 && !".".Equals(name)) {
                stack.Add(name);
            }
        }
        StringBuilder ans = new StringBuilder();
        if (stack.Count == 0) {
            ans.Append('/');
        } else {
            foreach (string name in stack) {
                ans.Append('/');
                ans.Append(name);
            }
        }
        return ans.ToString();
    }
}

Python3

class Solution:
    def simplifyPath(self, path: str) -> str:
        names = path.split("/")
        stack = list()
        for name in names:
            if name == "..":
                if stack:
                    stack.pop()
            elif name and name != ".":
                stack.append(name)
        return "/" + "/".join(stack)

C

char ** split(const char * s, char delim, int * returnSize) {
    int n = strlen(s);
    char ** ans = (char **)malloc(sizeof(char *) * n);
    int pos = 0;
    int curr = 0;
    int len = 0;
    
    while (pos < n) {
        while (pos < n && s[pos] == delim) {
            ++pos;
        }
        curr = pos;
        while (pos < n && s[pos] != delim) {
            ++pos;
        }
        if (curr < n) {
            ans[len] = (char *)malloc(sizeof(char) * (pos - curr + 1)); 
            strncpy(ans[len], s + curr, pos - curr);
            ans[len][pos - curr] = '\0';
            ++len;
        }
    }
    *returnSize = len;
    return ans;
}

char * simplifyPath(char * path){
    int namesSize = 0;
    int n = strlen(path);
    char ** names = split(path, '/', &namesSize);
    char ** stack = (char **)malloc(sizeof(char *) * namesSize);
    int stackSize = 0;
    for (int i = 0; i < namesSize; ++i) {
        if (!strcmp(names[i], "..")) {
            if (stackSize > 0) {
                --stackSize;
            } 
        } else if (strcmp(names[i], ".")){
            stack[stackSize] = names[i];
            ++stackSize;
        } 
    }
    
    char * ans = (char *)malloc(sizeof(char) * (n + 1));
    int curr = 0;
    if (stackSize == 0) {
        ans[curr] = '/';
        ++curr;
    } else {
        for (int i = 0; i < stackSize; ++i) {
            ans[curr] = '/';
            ++curr;
            strcpy(ans + curr, stack[i]);
            curr += strlen(stack[i]);
        }
    }
    ans[curr] = '\0';
    for (int i = 0; i < namesSize; ++i) {
        free(names[i]);
    }
    free(names);
    free(stack);
    return ans;
}

Golang

func simplifyPath(path string) string {
    stack := []string{}
    for _, name := range strings.Split(path, "/") {
        if name == ".." {
            if len(stack) > 0 {
                stack = stack[:len(stack)-1]
            }
        } else if name != "" && name != "." {
            stack = append(stack, name)
        }
    }
    return "/" + strings.Join(stack, "/")
}

JavaScript

var simplifyPath = function(path) {
    const names = path.split("/");
    const stack = [];
    for (const name of names) {
        if (name === "..") {
            if (stack.length) {
                stack.pop();
            } 
        } else if (name.length && name !== ".") {
            stack.push(name);

        }
    }
    
    return "/" + stack.join("/");
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串 path 的长度。
  • 空间复杂度:O(n),我们需要 O(n) 的空间存储 names 中的所有字符串。


BY /

本文作者:力扣

相关推荐

支持向量机SVM 分类和回归的实例

支持向量机(SupportVectorMachine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他...

Python scikit-learn机器学习教程

以下是scikit-learn的快速入门教程,涵盖机器学习的基本流程和常见操作,帮助你快速上手使用Python进行机器学习任务。1.环境安装bashpipinstallnumpypandas...

【机器学习】SVM支持向量机

一、SVM相关概念1.1通俗易懂的SVM算法描述SVM(支撑向量机)呢,简单来说就是在两类数据中间找一条“最宽的路”。这条路的中间线就是用来分类的边界(也叫“决策边界”),路越宽,分类的效果就...

Python NumPy库详解与应用

以下是scikit-learn的快速入门教程,涵盖机器学习的基本流程和常见操作,帮助你快速上手使用Python进行机器学习任务。1.环境安装bashpipinstallnumpypandas...

Linux下Qt桌面应用的开发流程

在Linux下开发Qt桌面应用的完整流程可分为以下六个核心阶段,结合Qt框架特性和Linux环境特点进行优化。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎洽谈合作。一、环境搭建与配置1安装...

Qt5 C++入门教程-第13章 自定义控件(Custom Widgets)

大道至简,在Qt5C++入门教程的这一部分,我们将创建一个自定义部件。大多数工具包通常仅提供诸如按钮、文本部件或滑块等最常见的部件。没有哪个工具包能够提供所有可能的部件。程序员必须自行创建此类部件...

Qt/C++开发经验小技巧291-295

国内站点:[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)国际站点:[https://github.com/fe...

Qt/C++音视频开发61-多屏渲染/解码渲染到多个窗口/画面实时同步

一、前言多屏渲染就是一个解码线程对应多个渲染界面,通过addrender这种方式添加多个绘制窗体,我们经常可以在展会或者卖电视机的地方可以看到很多电视播放的同一个画面,原理应该类似,一个地方负责打开解...

14个Qt开源项目推荐(持续更新)

1、Qt-Advanced-Docking-System【Qt开源项目推荐】完美的Dock窗口布局解决方案Qt-Advanced-Docking-System【GitHub地址】https://g...

关于Qt中的qss样式表需要注意的坑

关于QSS要注意的坑。-qss源自css,相当于css的一个子集,主要支持的是css2标准,很多网上的css3的标准的写法在qss这里是不生效的,所以不要大惊小怪。-qss也不是完全支持所有的cs...

以麒麟音乐为例,教你如何构建专属自己的音乐播放器

关注优麒麟,更多干货等着你!麒麟音乐是一款设计美观、功能简洁、支持多种音乐格式的音乐播放器。在播放本地音乐的同时,还可以根据用户喜好、自定义歌单来对音乐进行分组。除常规模式外,麒麟音乐还有小窗口模式来...

Qt Quick 和 Widgets 的对比

概念:QtQuick:QML类型和功能的标准库QtQuick模块:提供可视化组件,模型视图支持,动画框架以及用于构建用户界面的更多功能。QtQuickControls:基于Qt...

Qt创建项目实战之手把手创建第一个Qt项目

创建项目有两个入口,一个是在欢迎页面的projects中点击New(新建)按钮,另一个是点击标题栏中的文件,在文件下拉列表中点击新建文件或项目。选择模板点击新建以后,会弹出一个模板选择窗口,我们这里应...

Qt widget vs Qt Quick

Widgets适合传统桌面程序QtQuick是Qt4.7主推的技术Qt官网介绍:QtQuick是一种高级用户界面技术,使用它可轻松用于移动开发、嵌入式设备使用的动态触摸式界面和轻量级...

wxPython - 布局管理简介及绝对位置布局

实战wxPython系列-009一个典型的GUI程序的窗口界面中,一般是由各种控件(或者部件)组成,这些部件一般都会按一定的布局呈现在窗口中。布局方式可以分为绝对定位布局和相对定位布局,绝对定位布局中...