Java&C++题解与拓展——leetcode385.迷你语法分析器【么的新知识】

210 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

每日一题做题记录,参考官方和三叶的题解

题目要求

image.png

代码注释

image.png 总结一下就是:

  • 定义了一个名叫NestedInteger的类;
  • 初始化调用NestedInteger(value)
  • isInteger():是否仅包含单个整数;
  • getInteger():返回单个整数或nullnull
  • setInteger(value):使嵌套列表对象仅包含单个整数;
  • add(ni):在当前嵌套列表中添加新的嵌套列表nini
  • getList():返回嵌套列表,若为单个整数返回nullnull

思路一:栈

有点类似计算器的那个方法,运算符([[ & ]])和数字压入栈进行处理。

  • ,:跳过,遍历下一位
  • -数字
  • [
  • ]

Java

class Solution {
    int INF = 1000001;
    public NestedInteger deserialize(String s) {
        Deque<NestedInteger> stack = new ArrayDeque<>();
        char[] cs = s.toCharArray();
        int n = cs.length, i = 0;
        while(i < n) {
            if(cs[i] == ',' && ++i >= 0) //“,”跳过
                continue;
            if(cs[i] == '-' || (cs[i] >='0' && cs[i] <= '9')) { //负号或数字
                int j = i + 1;
                while(j < n && (cs[j] >= '0' && cs[j] <= '9')) //取出当前数字
                    j++;
                stack.addLast(new NestedInteger(Integer.parseInt(s.substring(i,j))));
                i = j;
            }
            else if(cs[i] == '[') {
                stack.addLast(new NestedInteger());
                stack.addLast(new NestedInteger(INF));
                i++;
            }
            else { //“]”
                List<NestedInteger> res = new ArrayList<>();
                while(!stack.isEmpty()) {
                    NestedInteger cur = stack.pollLast(); //括号中间元素
                    if(cur.isInteger() && cur.getInteger() == INF) //是单独整数则get
                        break; //不是单独整数证明未找到上一个'['匹配的']',继续寻找
                    res.add(cur); //括号中间元素加入答案
                }
                for(int j = res.size() - 1; j >= 0; j--)
                    stack.peekLast().add(res.get(j)); //在栈顶元素末尾添加当前答案内容
                i++;
            }
        }
        return stack.peekLast();
    }
}
  • 时间复杂度:O(n)O(n),遍历每一位。
  • 空间复杂度:O(n)O(n),栈的深度最大为nn,以及toCharArraycscs长度为nn

C++

class Solution {
    int INF = 1000001;
public:
    NestedInteger deserialize(string s) {
        stack<NestedInteger> stack;
        int n = s.size(), i = 0;
        while(i < n) {
            if(s[i] == ',' && ++i >= 0) //“,”跳过
                continue;
            if(s[i] == '-' || (s[i] >='0' && s[i] <= '9')) { //负号或数字
                int j = i + 1;
                while(j < n && (s[j] >= '0' && s[j] <= '9')) //取出当前数字
                    j++;
                stack.emplace(NestedInteger(stoi(s.substr(i, j - i + 1))));
                i = j;
            }
            else if(s[i] == '[') {
                stack.emplace(NestedInteger());
                stack.emplace(NestedInteger(INF));
                i++;
            }
            else { //“]”
                vector<NestedInteger> res;
                while(!stack.empty()) {
                    NestedInteger cur = stack.top(); //括号中间元素
                    stack.pop();
                    if(cur.isInteger() && cur.getInteger() == INF) //是单独整数则get
                        break; //不是单独整数证明未找到上一个'['匹配的']',继续寻找
                    res.push_back(cur); //括号中间元素加入答案
                }
                for(int j = res.size() - 1; j >= 0; j--)
                    stack.top().add(res.at(j)); //在栈顶元素末尾添加当前答案内容
                i++;
            }
        }
        return stack.top();
    }
};
  • 时间复杂度:O(n)O(n),遍历每一位。
  • 空间复杂度:O(n)O(n),栈的深度最大为nn

思路二:递归

由题目和注释部分代码可知,NestedInteger内部要么是一个整数,要么是一堆整数构成的嵌套列表,明显是个递归定义,所以可以递归来遍历【DFS】:

  • [:表示解析嵌套列表,递归解析;
  • ,:嵌套列表内还有其他元素,需继续解析;
  • ]:当前列表解析完毕;
  • -数字:当前对象内仅包含一个整数,遍历后返回。

【用了和上面不一样的方法取数字,上面是找到位数返回子串转int(需额外标号统计位数),下面是逐位加回去(需额外变量存当前数,且负数需标记)】

Java

class Solution {
    int idx = 0;
    public NestedInteger deserialize(String s) {
        char[] cs = s.toCharArray();
        if(cs[idx] == '[') { //新的待解析对象
            idx++;
            NestedInteger ni = new NestedInteger();
            while(cs[idx] != ']') { //解析完毕
                ni.add(deserialize(s));
                if(cs[idx] == ',') //还有其他元素
                    idx++;
            }
            idx++;
            return ni;
        }
        else { //单个数字
            boolean neg = false; //负数标识
            if(cs[idx] == '-') {
                neg = true;
                idx++;
            }
            //将数字位加成一个整数,也可如思路一统计位数返回子字符串转int
            int num = 0;
            while(idx < cs.length && Character.isDigit(cs[idx])) {
                num = num * 10 + cs[idx] - '0';
                idx++;
            }
            if(neg)
                num *= -1;
            return new NestedInteger(num); //返回相应单个数字
        }
    }
}
  • 时间复杂度:O(n)O(n),遍历每一位。
  • 空间复杂度:O(n)O(n),深度优先搜索的深度最大为nn

C++

class Solution {
public:
    int idx = 0;
    NestedInteger deserialize(string s) {
        if(s[idx] == '[') { //新的待解析对象
            idx++;
            NestedInteger ni;
            while(s[idx] != ']') { //解析完毕
                ni.add(deserialize(s));
                if(s[idx] == ',') //还有其他元素
                    idx++;
            }
            idx++;
            return ni;
        }
        else { //单个数字
            bool neg = false; //负数标识
            if(s[idx] == '-') {
                neg = true;
                idx++;
            }
            //将数字位加成一个整数,也可如思路一统计位数返回子字符串转int
            int num = 0;
            while(idx < s.size() && isdigit(s[idx])) {
                num = num * 10 + s[idx] - '0';
                idx++;
            }
            if(neg)
                num *= -1;
            return NestedInteger(num); //返回相应单个数字
        }
    }
};
  • 时间复杂度:O(n)O(n),遍历每一位。
  • 空间复杂度:O(n)O(n),深度优先搜索的深度最大为nn

总结

其实也是模拟题,模拟了好几天了……
题目自己定义了一个数据类型,要弄明白嵌套的是NestedInteger而不是int


欢迎指正与讨论!