「前端刷题」71. 简化路径

424 阅读4分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」。

题目

链接:leetcode-cn.com/problems/si…

给你一个字符串 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 风格绝对路径。

解题思路

思路1

path'/'分割成数组,如 /a/./b/../../c/分割成[ '', 'a', '.', 'b', '..', '..', 'c', '' ]。 新建一个栈stack为当前的路径,遍历path分割后的数组元素:

  • 遇到正常的字母时,推入 stack
  • 遇到 .. 时,stack 弹出最近一个路径
  • 遇到 . 或者为空时,不修改当前 stack。
  • 最后返回 '/' + stack.join('/') 为新的路径
var simplifyPath = function(path) {
    const stack = [];
    const pathArr = path.split('/');
    
    for (let item of pathArr) {
        if (item === '' || item === '.') {
            continue;
        } else if (item === '..') {
            stack.pop();
        } else {
            stack.push(item);
        }
    }

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

思路2

顺序栈

  • Unix 风格

    • 一个点 (.) , 表示当前目录.
    • 两个点 (..) , 表示上一级目录.
    • 可以出现连续斜杠 (/)
  • 规范路径

    • / 开头
    • 两个目录之间, 只有一个斜杠.
    • 最后一个目录名(如果存在), 不以 / 结尾.
    • 为 Unix 风格最短字符串 ()
  • 使用 arr.split() 方法, 以斜杠 (/) 为分隔符, 将 Unix 路径 path 拆分为若干字符串组成的数组.

  • 将字符串顺序压入栈中

  • 不包含元素, 一个点 (.) 时, 跳过.

  • 两个点 (..) 时, 将当前栈顶元素移出栈.

/**
 * @param {string} path
 * @return {string}
 */
class Stack {
    constructor() {
        this._top = 0;
        this._data = [];
    }
    push(element) {
        this._top ++;
        return this._data.push(element);
    }
    pop() {
        this._top --;
        return this._data.pop();
    }
    join(symbol) {
        this._top = 1;
        return this._data.join(symbol);
    }
}
var simplifyPath = function(path) {
    let stack = new Stack();
    let pathArr = path.split('/');
    for (let eachStr of pathArr) {
        if (eachStr == '' || eachStr == '.') {
            continue;
        } else if (eachStr == '..') {
            stack.pop();
        } else {
            stack.push(eachStr);
        }
    }
    return '/' + stack.join('/');
}
复杂度分析
  • 时间复杂度: O(n), n = path.split('/').length .
  • 空间复杂度: O(n), n = path.split('/').length .

数组长度

  • JavaScript 数组的长度可以是无限的, 只要内存允许的话. 数组的初始长度可以设置, 如果需要, 随后该长度可以自动增长. 使用数字串当作数组的索引, 等价于直接使用数字索引.

  • JavaScript 数组实际上是个 Key-Value 对. Key 不仅可以使数字, 还可以是其它对象.

var arr = new Array(2);
  arr[0] = 1;
  arr['second'] = 2;
  arr['third'] = 3;
  console.log(arr['0'] + ' ' + arr['second'] + [' '] + arr['third']);
  console.log(arr.length);
  /**
   * console:
       1 2 3
       2
   */

思路3

链式栈

/**
 * @param {string} path
 * @return {string}
 */
class Node {
    constructor (element) {
        this.element = element
        this.next = null
    }
}
class Stack {
    constructor() {
        this._top = null;
    }
    push(element) {
        let node = new Node(element);
        if (this._top == null) {
            this._top = node;
        } else {
            node.next = this._top;
            this._top = node;
        }
    }
    pop() {
        if (this._top == null) {
            return -1;
        }
        let element = this._top.element;
        this._top = this._top.next;
        element = null;
    }
    display() {
        let res = '';
        if (this._top != null) {
            let tmp = this._top;
            res = tmp.element;
            tmp = tmp.next;
            while (tmp != null) {
                res = tmp.element + '/' + res;
                tmp = tmp.next;
            }
        }
        return '/' + res;
    }
}
var simplifyPath = function(path) {
    let stack = new Stack();
    let pathArr = path.split('/');
    for (let eachStr of pathArr) {
        if (eachStr == '' || eachStr == '.') {
            continue;
        } else if (eachStr == '..') {
            stack.pop();
        } else {
            stack.push(eachStr);
        }
    }
    return stack.display();
}
  • JavaScript 链式栈优点
    • 一般, 链式栈与顺序栈相比, 优点是可以动态扩容.
      • 不过, JavaScript 数组长度是无限的, 只要内存允许. 即使设置了数组长度, 如果需要的话, 随后该长度也可以自动增长. 无需担心溢出.
        • 所以, 在 JavaScript 中, 链式栈的优点
          • 插入, 删除灵活
          • 物理地址不必相连