栈题目:迷你语法分析器

题目

标题和出处

标题:迷你语法分析器

出处:385. 迷你语法分析器

难度

6 级

题目描述

要求

给定一个字符串 s \texttt{s} s,表示嵌套列表的序列化,实现一个语法分析器,将嵌套列表反序列化并返回反序列化后的 NestedInteger \texttt{NestedInteger} NestedInteger 对象。

每个元素都是一个整数或者一个列表,列表中的元素也是整数或者其他列表。

示例

示例 1:

输入: s   =   "324" \texttt{s = "324"} s = "324"
输出: 324 \texttt{324} 324
解释:你应该返回一个 NestedInteger \texttt{NestedInteger} NestedInteger 对象,其中只包含一个整数 324 \texttt{324} 324

示例 2:

输入: s   =   "[123,[456,[789]]]" \texttt{s = "[123,[456,[789]]]"} s = "[123,[456,[789]]]"
输出: [123,[456,[789]]] \texttt{[123,[456,[789]]]} [123,[456,[789]]]
解释:返回一个 NestedInteger \texttt{NestedInteger} NestedInteger 对象,其中包含一个有 2 \texttt{2} 2 个元素的嵌套列表:

  1. 一个整数 123 \texttt{123} 123
  2. 一个包含 2 \texttt{2} 2 个元素的嵌套列表:
     i. 一个整数 456 \texttt{456} 456
     ii. 一个包含 1 \texttt{1} 1 个元素的嵌套列表:
      a. 一个整数 789 \texttt{789} 789

数据范围

  • 1 ≤ s.length ≤ 5 × 10 4 \texttt{1} \le \texttt{s.length} \le \texttt{5} \times \texttt{10}^\texttt{4} 1s.length5×104
  • s \texttt{s} s 由数字、方括号 "[]" \texttt{"[]"} "[]"、负号 ‘-’ \texttt{`-'} ‘-’ 和逗号 ‘,’ \texttt{`,'} ‘,’ 组成
  • s \texttt{s} s 是有效的 NestedInteger \texttt{NestedInteger} NestedInteger 对象的序列化
  • 输入中的所有值都在范围 [-10 6 ,   10 6 ] \texttt{[-10}^\texttt{6}\texttt{, 10}^\texttt{6}\texttt{]} [-106, 106]

解法

思路和算法

题目要求实现一个语法分析器,将给定的字符串 s s s 反序列化得到一个 NestedInteger \texttt{NestedInteger} NestedInteger 对象。以下将 NestedInteger \texttt{NestedInteger} NestedInteger 类型的对象称为「嵌套对象」,每个嵌套对象可能是整数或整数嵌套列表。

字符串 s s s 是一个有效嵌套对象的序列化,根据 s s s 的第一个字符,对应的嵌套对象有以下两种情况:

  • 第一个字符不是左方括号,则 s s s 对应的嵌套对象是一个整数,将 s s s 转成整数,创建该整数对应的嵌套对象并返回;

  • 第一个字符是左方括号,则 s s s 对应的嵌套对象是整数嵌套列表,需要对嵌套列表进行解析。

由于整数嵌套列表中的元素是整数或者其他整数嵌套列表,因此存在层级结构,可以使用栈实现语法分析器。

从左到右遍历字符串 s s s,对于不同的字符,处理方式分别如下:

  • 遇到负号或数字,表示遍历到一个整数,在遍历过程中维护整数的值;

  • 遇到左方括号,表示开始一个新的整数嵌套列表,将一个新的嵌套对象入栈;

  • 遇到右方括号或逗号,表示一个嵌套对象遍历完毕,如果该嵌套对象是整数,则将该整数加入栈顶的整数嵌套列表中;

    • 如果遇到右方括号且栈内元素个数大于 1 1 1,则用 list \textit{list} list 表示以当前右方括号结尾的整数嵌套列表,将 list \textit{list} list 出栈并加入新的栈顶元素(即 list \textit{list} list 的上一层整数嵌套列表)。

遍历结束后,栈内只有 1 1 1 个元素,该元素即为反序列化后的嵌套对象。

以下用例子 s = “[2,5,[-10,[-25],50]]" s = \text{``[2,5,[-10,[-25],50]]"} s=“[2,5,[-10,[-25],50]]" 说明解码过程。

  1. 遇到第一个左方括号,将一个嵌套对象入栈,此时栈内元素为 [ ] [] [],左边为栈底,右边为栈顶。

  2. 遇到整数 2 2 2 5 5 5,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] [2, 5] [2,5]

  3. 遇到第二个左方括号,将一个嵌套对象入栈,此时栈内元素为 [ 2 , 5 ] , [ ] [2, 5], [] [2,5],[]

  4. 遇到整数 − 10 -10 10,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] , [ − 10 ] [2, 5], [-10] [2,5],[10]

  5. 遇到第三个左方括号,将一个嵌套对象入栈,此时栈内元素为 [ 2 , 5 ] , [ − 10 ] , [ ] [2, 5], [-10], [] [2,5],[10],[]

  6. 遇到整数 − 25 -25 25,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] , [ − 10 ] , [ − 25 ] [2, 5], [-10], [-25] [2,5],[10],[25]

  7. 遇到第一个右方括号(和第三个左方括号匹配),将栈顶的整数嵌套列表出栈并加入新的栈顶元素,此时栈内元素为 [ 2 , 5 ] , [ − 10 , [ − 25 ] ] [2, 5], [-10, [-25]] [2,5],[10,[25]]

  8. 遇到整数 50 50 50,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] , [ − 10 , [ − 25 ] , 50 ] [2, 5], [-10, [-25], 50] [2,5],[10,[25],50]

  9. 遇到第二个右方括号(和第二个左方括号匹配),将栈顶的整数嵌套列表出栈并加入新的栈顶元素,此时栈内元素为 [ 2 , 5 , [ − 10 , [ − 25 ] , 50 ] ] [2, 5, [-10, [-25], 50]] [2,5,[10,[25],50]]

  10. 遇到第三个右方括号(和第一个左方括号匹配),此时栈内只有 1 1 1 个元素,该元素即为反序列化后的嵌套对象。

代码

class Solution {
    public NestedInteger deserialize(String s) {
        if (s.charAt(0) != '[') {
            return new NestedInteger(Integer.parseInt(s));
        }
        Deque<NestedInteger> stack = new ArrayDeque<NestedInteger>();
        int num = 0;
        int sign = 1;
        boolean flag = false;
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            if (c == '[') {
                stack.push(new NestedInteger());
            } else if (c == ']' || c == ',') {
                if (flag) {
                    stack.peek().add(new NestedInteger(num));
                    num = 0;
                    sign = 1;
                    flag = false;
                }
                if (c == ']' && stack.size() > 1) {
                    NestedInteger list = stack.pop();
                    stack.peek().add(list);
                }
            } else if (c == '-') {
                sign = -1;
            } else {
                num = num * 10 + (c - '0') * sign;
                flag = true;
            }
        }
        return stack.pop();
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,每个字符的操作时间都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。空间复杂度主要取决于栈空间,栈内的嵌套对象空间复杂度是 O ( n ) O(n) O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值