题目
标题和出处
标题:解析布尔表达式
难度
6 级
题目描述
要求
布尔表达式是运算结果为 true \texttt{true} true 或 false \texttt{false} false 的表达式。其可能的形式如下:
- "t" \texttt{"t"} "t",运算结果为 true \texttt{true} true;
- "f" \texttt{"f"} "f",运算结果为 false \texttt{false} false;
- "!(subExpr)" \texttt{"!(subExpr)"} "!(subExpr)",对内部表达式 subExpr \texttt{subExpr} subExpr 进行逻辑非的运算;
- "&(subExpr 1 , subExpr 2 , … , subExpr n )" \texttt{"\&(subExpr}_\texttt{1}\texttt{, subExpr}_\texttt{2}\texttt{, \ldots, subExpr}_\texttt{n}\texttt{)"} "&(subExpr1, subExpr2, …, subExprn)",对内部表达式 subExpr 1 , subExpr 2 , … , subExpr n \texttt{subExpr}_\texttt{1}\texttt{, subExpr}_\texttt{2}\texttt{, \ldots, subExpr}_\texttt{n} subExpr1, subExpr2, …, subExprn 进行逻辑与的运算,其中 n ≥ 1 \texttt{n} \ge \texttt{1} n≥1;
- "|(subExpr 1 , subExpr 2 , … , subExpr n )" \texttt{"|(subExpr}_\texttt{1}\texttt{, subExpr}_\texttt{2}\texttt{, \ldots, subExpr}_\texttt{n}\texttt{)"} "|(subExpr1, subExpr2, …, subExprn)",对内部表达式 subExpr 1 , subExpr 2 , … , subExpr n \texttt{subExpr}_\texttt{1}\texttt{, subExpr}_\texttt{2}\texttt{, \ldots, subExpr}_\texttt{n} subExpr1, subExpr2, …, subExprn 进行逻辑或的运算,其中 n ≥ 1 \texttt{n} \ge \texttt{1} n≥1。
给定一个表示布尔表达式的字符串 expression \texttt{expression} expression,返回该表达式的运算结果。
保证给定的表达式是有效的并遵循给定的规则。
示例
示例 1:
输入:
expression
=
"&(|(f))"
\texttt{expression = "\&(|(f))"}
expression = "&(|(f))"
输出:
false
\texttt{false}
false
解释:
首先计算
|(f)
\texttt{|(f)}
|(f) 得到
f
\texttt{f}
f。表达式变成
"&(f)"
\texttt{"\&(f)"}
"&(f)"。
其次计算
&(f)
\texttt{\&(f)}
&(f) 得到
f
\texttt{f}
f。表达式变成
f
\texttt{f}
f。
最终,返回
false
\texttt{false}
false。
示例 2:
输入:
expression
=
"|(f,f,f,t)"
\texttt{expression = "|(f,f,f,t)"}
expression = "|(f,f,f,t)"
输出:
true
\texttt{true}
true
解释:
false
OR
false
OR
false
OR
true
\texttt{false OR false OR false OR true}
false OR false OR false OR true 的运算结果是
true
\texttt{true}
true。
示例 3:
输入:
expression
=
"!(&(f,t))"
\texttt{expression = "!(\&(f,t))"}
expression = "!(&(f,t))"
输出:
true
\texttt{true}
true
解释:
首先计算
&(f,t)
\texttt{\&(f,t)}
&(f,t) 得到
f
\texttt{f}
f。表达式变成
"!(f)"
\texttt{"!(f)"}
"!(f)"。
其次计算
!(f)
\texttt{!(f)}
!(f) 得到
t
\texttt{t}
t。表达式变成
t
\texttt{t}
t。
最终,返回
true
\texttt{true}
true。
数据范围
- 1 ≤ expression.length ≤ 2 × 10 4 \texttt{1} \le \texttt{expression.length} \le \texttt{2} \times \texttt{10}^\texttt{4} 1≤expression.length≤2×104
- expression[i] \texttt{expression[i]} expression[i] 为以下字符之一: ‘(’ \texttt{`('} ‘(’、 ‘)’ \texttt{`)'} ‘)’、 ‘&’ \texttt{`\&'} ‘&’、 ‘|’ \texttt{`|'} ‘|’、 ‘!’ \texttt{`!'} ‘!’、 ‘t’ \texttt{`t'} ‘t’、 ‘f’ \texttt{`f'} ‘f’ 和 ‘,’ \texttt{`,'} ‘,’
解法
思路和算法
布尔表达式中,每个逻辑运算符(与、或、非)都对后面的一对括号内的内部表达式进行运算。由于需要根据每一对匹配的括号进行解析和运算,寻找匹配的括号需要借助栈的数据结构,因此可以使用栈实现解析布尔表达式。
由于布尔表达式中的逗号的作用是分隔内部表达式,并不影响布尔表达式的结果,因此可以跳过逗号,只对非括号字符解析和运算。
从左到右遍历布尔表达式 expression \textit{expression} expression,遇到非逗号且非右括号的字符则入栈,遇到右括号则开始解析,解析过程如下。
-
将栈内的元素依次出栈,直到遇到左括号,计算出栈的 ‘t’ \text{`t'} ‘t’ 和 ‘f’ \text{`f'} ‘f’ 的个数。
-
将左括号出栈,然后将逻辑运算符出栈。
-
根据逻辑运算符计算当前内部表达式的值:
-
如果逻辑运算符是 ‘&’ \text{`\&'} ‘&’,则是逻辑与运算,当 ‘f’ \text{`f'} ‘f’ 的个数等于 0 0 0 时,内部表达式的值为 ‘t’ \text{`t'} ‘t’,否则内部表达式的值为 ‘f’ \text{`f'} ‘f’。
-
如果逻辑运算符是 ‘|’ \text{`|'} ‘|’,则是逻辑或运算,当 ‘t’ \text{`t'} ‘t’ 的个数大于 0 0 0 时,内部表达式的值为 ‘t’ \text{`t'} ‘t’,否则内部表达式的值为 ‘f’ \text{`f'} ‘f’。
-
如果逻辑运算符是 ‘!’ \text{`!'} ‘!’,则是逻辑非运算,当 ‘f’ \text{`f'} ‘f’ 的个数大于 0 0 0 时,内部表达式的值为 ‘t’ \text{`t'} ‘t’,否则内部表达式的值为 ‘f’ \text{`f'} ‘f’。
-
-
将内部表达式的值入栈。
重复上述操作,直到遍历完毕布尔表达式。
由于 expression \textit{expression} expression 是有效的布尔表达式,因此一定能正确解析,遍历结束时,栈内只有一个元素,为布尔表达式的结果。如果栈内的元素是 ‘t’ \text{`t'} ‘t’,返回 true \text{true} true,否则返回 false \text{false} false。
代码
class Solution {
public boolean parseBoolExpr(String expression) {
Deque<Character> stack = new ArrayDeque<Character>();
int length = expression.length();
for (int i = 0; i < length; i++) {
char c = expression.charAt(i);
if (c == ',') {
continue;
} else if (c == ')') {
int tCount = 0, fCount = 0;
while (stack.peek() != '(') {
char prev = stack.pop();
if (prev == 't') {
tCount++;
} else if (prev == 'f') {
fCount++;
}
}
stack.pop();
char op = stack.pop();
if (op == '&') {
char curr = fCount == 0 ? 't' : 'f';
stack.push(curr);
} else if (op == '|') {
char curr = tCount > 0 ? 't' : 'f';
stack.push(curr);
} else if (op == '!') {
char curr = fCount > 0 ? 't' : 'f';
stack.push(curr);
}
} else {
stack.push(c);
}
}
return stack.pop() == 't';
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是布尔表达式 expression \textit{expression} expression 的长度。需要遍历布尔表达式一次,每个字符最多入栈和出栈各一次。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是布尔表达式 expression \textit{expression} expression 的长度。空间复杂度主要取决于栈空间,栈内元素个数不会超过 n n n。