Simplify Path

Mar 02, 2019

第三天(hhh,好像又很久没刷了), 又AC掉了逻辑题,或者说又是一道用if else加状态机搞定的题。

今天的题目是71. Simplify Path

以后还是不copy题目到这里来了,有点麻烦的感觉。。。

对于这种纯看逻辑的题目,可以先分析一下给出的测例,然后通过题目来分析要注意什么:

  1. “/home/”
  2. “/../”
  3. “/home//foo/”
  4. “/a/./b/../../c/”
  5. “/a/../../b/../c//.//”
  6. “/a//b////c/d//././/..”

从上面我们大概可以知道要注意的一些点有:

  • 首先疑似最开始的符号一定是'/'?
  • 通过/来分割单词,这意味着我们可以用python中的split或者先做一次遍历来分割单词,这样做会简化逻辑(但我没用这种方法)
  • 要区分...
  • .表示当前目录,..表示上级目录
  • 遇到多个/,就当成一个

事实上在后面的测试中,我发现一个很坑的点,就是.....a这种并不是一个特殊的字符串,可以作为路径名。

我们现在尝试写一个基于状态机的方法,首先定义一下遍历时需要的状态:

  1. 前面是一个正常的字符
    • 遇到/,就插入到结果字符串中,并跳转到1
    • 遇到.,就跳转到2
    • 遇到一个正常的字符,插入到结果字符串中。
  2. 前面是/
    • 如果遇到一个/,就直接跳过
    • 如果遇到一个.,跳转到2
    • 如果是一个正常字符,就插入到结果字符串中并跳转到0
  3. 前面是.
    • 如果遇到一个/, 就跳转到1
    • 如果遇到一个.,就跳转到3
    • 如果遇到一个正常字符,就插入.和这个字符,并跳转到0
  4. 前面是..
    • 如果遇到一个/,就开始回溯删除到前面一个/
    • 其余则插入一个..和这个字符,并跳转到0
class Solution {
public:
    string simplifyPath(string path) {
        string res;
        
        // some flag to kepp state.
        int state = 0;  // 0: last char is [char]
                        // 1: last char is '/'
                        // 2: last char is '.'
                        // 3: last char is ".."
        
        if (path.size() != 0 && path[path.size()-1]!='/') path.push_back('/');
        
        int len = path.size();
        for(int i = 0; i < len; i++) {
            char c = path[i];
            
            if (state == 0) {
                if (c == '/') { res.push_back('/'); state = 1; }
                else if (c == '.') state = 2;
                else res.push_back(c);
            } else if (state == 1) {
                if (c == '/') {}
                else if (c == '.') { state = 2; }
                else {
                    res.push_back(c); state = 0;
                }
            } else if (state == 2) {
                if (c == '/') state = 1;
                else if (c == '.') {
                    // '..'
                    state = 3;
                } else {
                    res.push_back('.'); res.push_back(c); state = 0;
                }
            } else if (state == 3) {
                if (c == '/') {
                    // go back
                    res.pop_back(); // pop '/'
                    while(res.size() != 0 && *res.rbegin() != '/') {
                        res.pop_back(); // pop anthing until '/'
                    }
                    if (res.size() == 0) res.push_back('/');
                    state = 1;
                } else {
                    res.push_back('.'); 
                    res.push_back('.');
                    res.push_back(c);
                    state = 0;
                }
            }
            //cout << state << " " << c << " " << res <<  endl;
        }
        
        if ((state == 1 && res.size() != 1)) res.pop_back();
        return res;
    }
};

update at 2020-03-23

状态转移图:

FSM

这道题其实用栈会更简单一点:

string simplifyPath(string path) {
    
    vector<string> st;
    int beg = 0;
    path.push_back('/');
    for(int i = 0, sz = path.size(); i < sz; i++) {
        if (path[i] == '/') {
            auto s = path.substr(beg, i-beg);
            beg = i + 1;
            if (s == "." || s.size() == 0) {
                // do nothing
            } else if (s == "..") {
                if (st.size() != 0) st.pop_back(); // make sure '/../' is ok
            } else st.push_back(s);
        }
    }
    string res;
    for(auto &s: st) {
        // cout << s << endl;
        res.push_back('/');
        res += s;
    }
    if (res.size() == 0) res.push_back('/'); 
    return res;
}

stringstreamgetline来进行字符串分割:

string simplifyPath(string path) {
    string buf;
    istringstream ss(path);
    vector<string> st;
    while(getline(ss, buf, '/')) {
        // cout << buf << endl;
        if (buf == "." || buf.size() == 0) {

        } else if (buf == ".."){
            if (st.size() != 0) st.pop_back();
        }
        else st.push_back(buf);
    }
    string res;
    for (auto &s: st) {
        res.push_back('/');
        res += s;
    }
    if (res.size() == 0) res.push_back('/');
    return res;
}
LeetCodeLeetCodeStackFSMString

Spiral Matrix

ZigZag Conversion

comments powered by Disqus