题目
标题和出处
标题:迷你语法分析器
出处: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 个元素的嵌套列表:
- 一个整数 123 \texttt{123} 123。
- 一个包含
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} 1≤s.length≤5×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]]" 说明解码过程。
-
遇到第一个左方括号,将一个嵌套对象入栈,此时栈内元素为 [ ] [] [],左边为栈底,右边为栈顶。
-
遇到整数 2 2 2 和 5 5 5,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] [2, 5] [2,5]。
-
遇到第二个左方括号,将一个嵌套对象入栈,此时栈内元素为 [ 2 , 5 ] , [ ] [2, 5], [] [2,5],[]。
-
遇到整数 − 10 -10 −10,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] , [ − 10 ] [2, 5], [-10] [2,5],[−10]。
-
遇到第三个左方括号,将一个嵌套对象入栈,此时栈内元素为 [ 2 , 5 ] , [ − 10 ] , [ ] [2, 5], [-10], [] [2,5],[−10],[]。
-
遇到整数 − 25 -25 −25,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] , [ − 10 ] , [ − 25 ] [2, 5], [-10], [-25] [2,5],[−10],[−25]。
-
遇到第一个右方括号(和第三个左方括号匹配),将栈顶的整数嵌套列表出栈并加入新的栈顶元素,此时栈内元素为 [ 2 , 5 ] , [ − 10 , [ − 25 ] ] [2, 5], [-10, [-25]] [2,5],[−10,[−25]]。
-
遇到整数 50 50 50,将整数加入栈顶的整数嵌套列表,此时栈内元素为 [ 2 , 5 ] , [ − 10 , [ − 25 ] , 50 ] [2, 5], [-10, [-25], 50] [2,5],[−10,[−25],50]。
-
遇到第二个右方括号(和第二个左方括号匹配),将栈顶的整数嵌套列表出栈并加入新的栈顶元素,此时栈内元素为 [ 2 , 5 , [ − 10 , [ − 25 ] , 50 ] ] [2, 5, [-10, [-25], 50]] [2,5,[−10,[−25],50]]。
-
遇到第三个右方括号(和第一个左方括号匹配),此时栈内只有 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)。