leetcode 1106. 解析布尔表达式
xxleyi opened this issue · comments
给你一个以字符串形式表述的 布尔表达式(boolean) expression,返回该式的运算结果。
有效的表达式需遵循以下约定:
"t",运算结果为 True
"f",运算结果为 False
"!(expr)",运算过程为对内部表达式 expr 进行逻辑 非的运算(NOT)
"&(expr1,expr2,...)",运算过程为对 2 个或以上内部表达式 expr1, expr2, ... 进行逻辑 与的运算(AND)
"|(expr1,expr2,...)",运算过程为对 2 个或以上内部表达式 expr1, expr2, ... 进行逻辑 或的运算(OR)
示例 1:
输入:expression = "!(f)"
输出:true
示例 2:
输入:expression = "|(f,t)"
输出:true
示例 3:
输入:expression = "&(t,f)"
输出:false
示例 4:
输入:expression = "|(&(t,f,t),!(t))"
输出:false
提示:
1 <= expression.length <= 20000
expression[i] 由 {'(', ')', '&', '|', '!', 't', 'f', ','} 中的字符组成。
expression 是以上述形式给出的有效表达式,表示一个布尔值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/parsing-a-boolean-expression
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解:
此题是对前缀表达式进行求值。我们只需要依次入栈,并借助括号判断合适的子表达式求值时机。
求值子表达时,区分好运算符和运算数即可。
这道题的循环不变式如何体现呢?核心是洞察到后入先出的求值顺序,从而使用两个栈解决问题。这是不变的根本,有了这个,剩下的也变得很容易,无非是按部就班,分情况讨论。
/**
* @param {string} expression
* @return {boolean}
*/
var parseBoolExpr = function(expression) {
const stack = []
// 三种运算符的实现
const ops = {
// 多参
'&': (args) => args.every(e => e === 't'),
// 多参
'|': (args) => args.some(e => e === 't'),
// 单参
'!': (args) => args[0] === 'f',
}
// 最内层子表达式的求值
// 一直出栈,直至遇到一个运算符为止
// 并将求值结果压入老栈
function evaluateInnerPart() {
const args = []
let e
while (true) {
e = stack.pop()
if (e in ops) {
stack.push(ops[e](args) ? 't' : 'f')
return
}
args.push(e)
}
}
// 单趟循环,分情况处理
for (let e of expression) {
switch (e) {
// 遇到右括号,需要求值最内层子表达时
case ')':
evaluateInnerPart()
break
// 遇到逗号和左括号,直接跳过
case ',':
case '(':
break
// 其余为运算符或运算数,直接入栈
default:
stack.push(e)
}
}
// 循环过后,栈中唯一的运算数为整个表达式的求值结果
// 并将此结果转化为 JS 中的相应运算符
return stack.pop() === 't'
};