【LeetCode】布尔运算 [M](动态规划)

166 篇文章 0 订阅

面试题 08.14. 布尔运算 - 力扣(LeetCode)

一、题目

给定一个布尔表达式和一个期望的布尔结果 result,布尔表达式由 0 (false)、1 (true)、& (AND)、 | (OR) 和 ^ (XOR) 符号组成。实现一个函数,算出有几种可使该表达式得出 result 值的括号方法。

示例 1:
输入: s = "1^0|0|1", result = 0
输出: 2
解释: 两种可能的括号方法是
1^(0|(0|1))
1^((0|0)|1)

示例 2:
输入: s = "0&0&0&1^1|0", result = 1
输出: 10

提示:

  • 运算符的数量不超过 19 个

二、代码

class Solution {
    // 通过一个类封装两个信息,作为递归的返回值
    public class Info {
        // 最终计算结果为true的逻辑符号结合的方法数
        private int tCnt;
        // 最终计算结果为false的逻辑符号结合的方法数
        private int fCnt;

        public Info(int t, int f) {
            this.tCnt = t;
            this.fCnt = f;
        }
    }

     public int countEval(String s, int result) {
        // 过滤无效参数 
        if (s == null || s.length() == 0) {
            return 0;
        }

        char[] str = s.toCharArray();
        int n = str.length;
        // 引入Info类型的dp缓存
        Info[][] dp = new Info[n][n];

        Info info = process(str, 0, str.length - 1, dp);
        // 当前要求最终的结果为result,返回result结果的逻辑符号结合的方法数
        return result == 1 ? info.tCnt : info.fCnt;
    }

    // 限制:
	// L...R上,一定有奇数个字符
	// L位置的字符和R位置的字符,非0即1,不能是逻辑符号!
	// 返回str[L...R]这一段,为true的方法数,和false的方法数
    public Info process(char[] str, int l, int r, Info[][] dp) {
        // 先查看答案是否在缓存中,有的话就直接返回
        if (dp[l][r] != null) {
            return dp[l][r];
        }
        
        // 当前范围只有一个数
        if (l == r) {
            // 如果这个位置的数是1,那么true就有1个,false就有0个
            int t = str[l] == '1' ? 1 : 0;
            // 如果这个位置的数是0,那么true就有0个,false就有1个
            int f = str[l] == '0' ? 1 : 0;
            // 将结果存入dp
            dp[l][r] = new Info(t, f);
            return dp[l][r];
        } else {
            int t = 0;
            int f = 0;
            // 从范围上尝试所有的可能情况,i作为分割,将式子分成左右两个部分,然后分别去求不同左右两部分范围的结果,来累加出总的答案
            // i指向的就是式子中的运算逻辑符号,这里就是把当前范围上所有的逻辑符号都作为分隔位置尝试一边,将所有符合条件的结果都累加起来
            for (int i = l + 1; i < r; i += 2) {
                // 向下递归获取左右两部分的结果
                Info leftInfo = process(str, l, i - 1, dp);
                Info rightInfo = process(str, i + 1, r, dp);
                
                // 根据当前尝试的逻辑运算符号,来计算能让式子结果为true和false的方法数,并且累加到t和f中
                // &:左右两边都是true,最终结果才能是true;左右两边至少存在一个false或者两边都是false,最终结果就是false
                // |:左右两边都是至少存在一个true或者两边都是true,最终结果才能是true;左右两边至都是false,最终结果就是false
                // ^:左右两边结果不相同,最终结果才能是true;左右两边结果相同,最终结果就是false
                if (str[i] == '&') {
                    t += leftInfo.tCnt * rightInfo.tCnt;
                    f += leftInfo.tCnt * rightInfo.fCnt + leftInfo.fCnt * rightInfo.tCnt + leftInfo.fCnt * rightInfo.fCnt;
                } else if (str[i] == '|') {
                    t += leftInfo.tCnt * rightInfo.fCnt + leftInfo.fCnt * rightInfo.tCnt + leftInfo.tCnt * rightInfo.tCnt;
                    f += leftInfo.fCnt * rightInfo.fCnt;
                } else if (str[i] == '^') {
                    t += leftInfo.tCnt * rightInfo.fCnt + leftInfo.fCnt * rightInfo.tCnt;
                    f += leftInfo.fCnt * rightInfo.fCnt + leftInfo.tCnt * rightInfo.tCnt;
                }
            }
            // 将结果存入dp
            dp[l][r] = new Info(t, f);
            return dp[l][r];
        }
    }
}

三、解题思路 

左右两侧得到T、F的方法数,根据最后逻辑符号的不同来做组合.

可能会根据划分符号到底是&、|、^而不同。根据预期是True或者False可能表现形式也不同,但是左侧汇报True/ False的方法数,右侧汇报True/False的方法数,总能加工出来当前划分情况的结果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值