Simplify Path 4ms Java Solution

这是leetcode中一道在线编程题,原问题链接为

https://leetcode.com/problems/simplify-path/

原问题描述很简单,如下:
Given an absolute path for a file (Unix-style), simplify it.
For example,
path = “/home/”, => “/home”
path = “/a/./b/../../c/”, => “/c”

也就是简化Unix风格的文件的绝对路径,该问题难度不大,解决方案主要用 来解决,但是这里面存在的一些细节问题,使得快速编写出正确的solution也并不是那么轻松,接下来的任务就是整理这一过程,尽量使该问题的解决方案条理清晰。

首先对问题进行分析,Unix文件的绝对路径最简单的形式是“/#/#/…. /#”,其中#代表任意不包含‘/’(‘/’是Unix风格目录的分隔符)的字符串,且该字符串不为“.”和“..”。因为“.”代表当前目录,可省略;而“..”表上级目录,可以进一步简化,即“/#/#/..”可以简化为“/#/”,这就需要用到 的性质了。此外,需要注意的一点就是绝对路径最终的形式总是要以“/”为开头,否则为无效路径。

所以,我们算法可描述如下:

  1. 首先对原始的路径字符串path以“/”为分隔符,将其分为字符串数组。分割的方法可以是遍历字符串path的每个字符并以“/”为分割标志,也可以用Java中String自带的方法split()来分割。注意这两种方法存在效率差异,后面会有说明。

  2. 然后,按顺序从左到右对字符串数组进行栈操作,可能的字符串有{“”, “.”, “..”, 其他形式}, 其中

    • 若字符串为“”或“.”,不做任何处理;
    • 若字符串为“..”,则执行出栈 操作(注意,若栈为空,不做任何操作);
    • 否则, 执行压栈 操作。
  3. 最后,就是还原最终的路径了,将栈底至栈顶的字符串从左到右填进“/#/#/…. /#”格式中的“#”中去。

算法时间的复杂度为遍历字符串path中字符的时间,为O(n),n为path的长度。空间复杂度亦是O(n),因为最终需要返回至多为n长度的简单路径。
下面贴一下我的Java代码:

public class Solution {
    public String simplifyPath(String path) {
        int len = path.length();

        String[] stack = new String[len];
        int pop = -1;

        int index = 0;
        while (index < len) {
            if (path.charAt(index) == '/') {
                continue;
            }

            int tail = index;
            while (tail < len && path.charAt(tail) != '/')
                tail++;

            String sub = path.substring(index, tail);
            if (sub.equals("..")){
                if (pop >= 0) --pop;
            } else if (!sub.equals(".")) {
                stack[++pop] = sub;
            }

            index = tail + 1;
        }

        if(pop == -1) return "/";

        StringBuilder simplifiedPath = new StringBuilder();
        for (int i = 0; i <= pop; i++) {
            simplifiedPath.append("/");
            simplifiedPath.append(stack[i]);
        }
        return simplifiedPath.toString();
    }
}

上述代码没有用String自带的方法split()来分割字符串,而是通过直接遍历字符串中字符实现,在leetcode官网其完成252个测试用例用时4ms。

下边与用split()方法分割字符串对比一下性能。其代码实现如下:

public class Solution {
    public String simplifyPath(String path) {
        int len = path.length();
        String[] stack = new String[len];
        int pop = -1;

        String[] subs = path.split("/");
        for (int i = 0; i < subs.length; i++) {
            if (subs[i].equals("") || subs[i].equals(".")) continue;
            if (subs[i].equals("..")) {
                if (pop >= 0) --pop;
            }else 
                stack[++pop] = subs[i];
        }

        if(pop == -1) return "/";

        StringBuilder simplifiedPath = new StringBuilder();
        for (int i = 0; i <= pop; i++) {
            simplifiedPath.append("/");
            simplifiedPath.append(stack[i]);
        }
        return simplifiedPath.toString();
    }
}

在leetcode官网其完成252个测试用例用时8ms,速度要慢上一倍。因此,从性能优化的角度来考虑,除非必要,应该尽量避免使用split,split由于支持正则表达式,所以效率会比较低,调用频率太高将会耗费大量资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值