【程序员面试金典】面试题 08.14. 布尔运算

文章介绍了如何解决一道程序员面试题,即给定一个包含0、1和布尔运算符的表达式,计算得出期望结果的括号放置方法数量。通过使用动态规划的方法,按区间从小到大的顺序,对不同运算符(&,|,^)进行讨论,更新区间结果为0和1的方案数。给出了具体的代码实现和递推公式。
摘要由CSDN通过智能技术生成

【程序员面试金典】面试题 08.14. 布尔运算

题目描述

描述:给定一个布尔表达式和一个期望的布尔结果 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 个

解题思路

思路1:最直观的想法是,区间dp。使用dp[i][j][0]表示区间i~j计算结果为0的方案数,使用dp[i][j][1]表示区间i~j计算结果为1的方案数,然后分情况讨论。首先按照区间从小到大来遍历,假设区间长度为step+1(此处为了方便处理下标),其中i表示区间起始位置,j表示区间的运算符,以j为分割,将区间分为[i,j-1]与[j+1,i+step]。假如j为&,那么结果为0的情况有0/0、0/1和1/0,结果为1的情况有1/1;假如j为|,那么结果为0的情况有0/0,结果为1的情况有1/1、0/1和1/0;假如j为^,那么结果为0的情况有0/0和1/1,结果为1的情况有0/1和1/0。注意:由于表达式是数字和运算符间隔的,故i、j、step均是+=2;由于(i,i+step)可以分为多种区间情况,故递推公式为+=。

int countEval(string s, int result) 
{
   int n=s.size();
   //dp[i][j][0]表示i~j结果为0的方案数 dp[i][j][1]表示i~j结果为1的方案数
   vector<vector<vector<int>>> dp(n,vector<vector<int>>(n,vector<int>(2,0)));
   //初始化dp[i][i][0]和dp[i][i][1]
   for(int i=0;i<n;i+=2)
   {
      dp[i][i][0]=s[i]=='0'?1:0;
      dp[i][i][1]=s[i]=='1'?1:0;
   }
   //step表示表达式长度减去1 1^0|0|1
   //1 1^0 1^0|0 1^0|0|1
   //从小部分长度到大部分长度
   for(int step=0;step<n;step+=2)
   {
     //i表示表达式起始位置
     for(int i=0;i+step<n;i+=2)
     {
        //j表示表达式中的运算符 以j作为分割
        for(int j=i+1;j<i+step;j+=2)
        {
           //将step分为[i,j-1]以及[j+1,i+step]
           int left0=dp[i][j-1][0],left1=dp[i][j-1][1];
           int right0=dp[j+1][i+step][0],right1=dp[j+1][i+step][1];
           //第一种j=& 
           if(s[j]=='&')
           {
               //0: 0 0 ; 0 1 ; 1 0
               dp[i][i+step][0]+=left0*right0+left0*right1+left1*right0;
               //1: 1 1
               dp[i][i+step][1]+=left1*right1;
           }
           //第二种j=|
           else if(s[j]=='|')
           {
               //0: 0 0 
               dp[i][i+step][0]+=left0*right0;
               //1: 1 1 ; 0 1 ; 1 0
               dp[i][i+step][1]+=left1*right1+left0*right1+left1*right0;
           }
           //第三种j=^
           else if(s[j]=='^')
           {
              //0: 0 0 ; 1 1 
              dp[i][i+step][0]+=left0*right0+left1*right1;
              //1: 0 1 ; 1 0
              dp[i][i+step][1]+=left0*right1+left1*right0;
           }
        }
     }
  }
  return dp[0][n-1][result];
}

注意:按照区间从小到大来依次计算!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值