栈题目:解析布尔表达式

题目

标题和出处

标题:解析布尔表达式

出处:1106. 解析布尔表达式

难度

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} n1
  • "|(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} n1

给定一个表示布尔表达式的字符串 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} 1expression.length2×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,遇到非逗号且非右括号的字符则入栈,遇到右括号则开始解析,解析过程如下。

  1. 将栈内的元素依次出栈,直到遇到左括号,计算出栈的 ‘t’ \text{`t'} ‘t’ ‘f’ \text{`f'} ‘f’ 的个数。

  2. 将左括号出栈,然后将逻辑运算符出栈。

  3. 根据逻辑运算符计算当前内部表达式的值:

    • 如果逻辑运算符是 ‘&’ \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’

  4. 将内部表达式的值入栈。

重复上述操作,直到遍历完毕布尔表达式。

由于 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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

伟大的车尔尼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值