刷爆力扣的极简解法|71 简化路径:用栈三行代码秒掉 path 难题

上一章节,用栈解决了"删除相邻重复项",这一章节,继续用栈处理真实业务题。


📖 一、题目描述

LeetCode 71. 简化路径

给你一个字符串 path,表示一个 Unix 风格的绝对路径(以 '/' 开头),请你将其转换为 更简洁规范的路径

在 Unix 风格的文件系统中:

  • . 表示当前目录

  • .. 表示上一级目录

注意:路径中多个连续的斜杠 / 视为 单个斜杠;最后返回的路径必须以 / 开头,且 目录之间用单个 / 分隔,且路径末尾 不能有斜杠(路径只有根目录 / 的情况除外)。

示例

示例 1:

输入:"/home/"
输出:"/home"
解释:末尾多余的斜杠要去掉

示例 2:

输入:"/../"
输出:"/"
解释:从根目录向上一级是回不去的

示例 3:

输入:"/home//foo/"
输出:"/home/foo"
解释:连续的斜杠合并为单个

示例 4:

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

提示

  • 1 <= path.length <= 3000

  • 路径由英文字母、数字、'.''/''_' 组成

  • 路径保证是一个有效的 Unix 路径


🧠 二、思路讲解:为什么"栈"是这题的灵魂?

关键观察

题目其实就 3 种情况:

遇到的内容含义操作
""(空字符串)或 /没东西 / 分隔符跳过
.(一个点)当前目录跳过
..(两个点)返回上一级弹栈(前提:栈非空)
其他(如 homeab真实目录名压栈

是不是和 1047 删除相邻重复项一个套路?

没错!栈就是用来"配对/上下文消除/进退场景"问题的万能钥匙

上一题:相邻字母相同 → 配对消除(pop)
这一题:遇到 ".." → 回退一格(pop)

栈就像"逛文件夹的足迹"

想象你在逛电脑文件夹:

  • 进入 home → 📂 栈里压入 home

  • 进入 user → 📂 栈里压入 user

  • 进入 . → ⏭️ 当前目录,原地不动

  • 进入 .. → ⬆️ 回到上一级,user 弹出去

  • 最终栈里留下的,就是你"真正到达的位置"。

栈就 = 你走过的路径脚印


💻 三、代码实现

🔵 JavaScript 实现

用数组模拟栈(最常用,最清晰)
/**
 * @param {string} path
 * @return {string}
 */
function simplifyPath(path) {
    const stack = [];
​
    // 把路径按 '/' 切分 → 自动过滤掉多余的空字符串
    for (const dir of path.split('/')) {
        if (dir === '' || dir === '.') {
            continue;                            // 空字符串 / 当前目录 → 跳过
        }
        if (dir === '..') {
            stack.pop();                         // 上一级 → 弹栈
        } else {
            stack.push(dir);                     // 正常目录名 → 入栈
        }
    }
​
    return '/' + stack.join('/');                // 拼回规范路径
}

核心思路:

  • path.split('/') 自动把空段滤掉(虽然这里我们手动 continue 也滤,更稳)

  • 遇到 ..弹栈(如果栈空,就什么都不做,对应"回不去根目录")

  • 遇到真实目录名 → 入栈

  • 最后用 / 拼接,前面补 /

输入:"/a/./b/../../c/" 图文详解

文字版理解:

  1. 进入a文件夹,. 代表当前, 不需要写,

  2. 那么就是/a/b

  3. ../ 代表回退到上一层,目录变为 /a

  4. ../回退上一层,目录就是当前文件夹了

  5. 继续c进来,所以最后的目录是当前文件夹下的c === /c

对应数组一下解析图:


🐍 Python 实现

和 JavaScript 一样的两种思路,Python 写法更简洁。

用 list 模拟栈(最常用,最清晰)
class Solution:
    def simplifyPath(self, path: str) -> str:
        stack = []
​
        for dir in path.split('/'):
            # 空字符串 / '.' → 跳过
            if dir in ('', '.'):
                continue
            # '..' → 弹栈(栈空就不弹,等价于返回根目录)
            if dir == '..':
                if stack:
                    stack.pop()
            # 真实目录名 → 入栈
            else:
                stack.append(dir)
​
        return '/' + '/'.join(stack)

Python 特性:

  • path.split('/') 自动拆分,空字符串会保留

  • if stack:if len(stack) > 0 更 Pythonic

  • '/'.join(stack) 拼接目录,优雅又高效

  • 核心逻辑 5 行代码,秒杀 90% 的提交


⏱️ 四、复杂度分析

  1. 时间复杂度:代码跑得有多快(看循环跑了几次)

  2. 空间复杂度:代码占了多少额外内存(除了输入,还申请了啥)


split + 数组栈

维度结论小白版解释
⏱️ 时间复杂度O(n)字符串长 n,split 切一遍 O(n),再扫一遍栈 O(n)
💾 空间复杂度O(n)split 拆出 O(n) 个段,stack 最坏装 O(n) 个目录

怎么数时间复杂度?

stack = []                          # O(1)
for dir in path.split('/'):         # 字符串多长,这个 for 就跑几次 → O(n)
    if dir in ('','.'): continue    # 判断是 O(1)
    if dir == '..': stack.pop()     # pop 是 O(1)
    else: stack.append(dir)         # append 是 O(1)
return '/' + '/'.join(stack)        # join 把栈拼回去 → O(n)

总体 = O(n) + O(n) = O(n),这就是时间复杂度。

怎么数空间复杂度?

不用想复杂,只数额外申请了啥

申请的东西算不算额外空间
输入的字符串 path❌ 不算
split 拆出来的数组✅ 算
自己 new 的 stack 列表✅ 算
几个临时变量(istart 等)❌ 不算(就几个)

额外申请了一个 split 数组 + 一个 stack 列表,最坏装 n 个目录 → O(n)


🎁 五、彩蛋:这题还能怎么拓展?

🔗 拓展题推荐

1️⃣ LeetCode 20. 有效的括号 —— 栈的入门题(上一篇已讲解) 2️⃣ LeetCode 1047. 删除相邻重复项 —— 栈的"消除"用法(上一篇已讲解) 3️⃣ LeetCode 1190. 反转每对括号间的子串 —— 栈 + 字符串构造 4️⃣ LeetCode 394. 字符串解码 —— "栈的栈"经典题 5️⃣ LeetCode 224. 基本计算器 —— 栈 + 表达式求值

核心套路: 遇到"路径 / 括号 / 嵌套 / 进退"字眼,第一反应是栈!

💼 真实业务场景

这题看似冷门,实则 大厂面试常客 + 实战必备

  • 📂 Git 操作git log --graph 输出路径简化

  • 🐳 Docker:容器路径解析

  • ☁️ 云服务:对象存储的 OSS Key 处理

  • 🖥️ 前端路由:Vue/React 路由匹配时简化 URL

学会了这一题,等于打通了一类问题的任督二脉。

💡 面试加分项

如果你面试时碰到这题,编编建议你:

  1. 先说思路:这题是"路径进退"问题,栈是天然解法

  2. 先写常规写法:split + 数组模拟栈,清晰易懂

  3. 提一句边界:路径可能以多个 / 结尾、从根目录 .. 出不去、栈空要保护

  4. 举一反三:提一句"这类路径/进退问题都能用栈做"


📌 关注编编,下期带你:

下期,继续拆解算法 🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值