给定一个布尔表达式和一个期望的布尔结果 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 个
分析:
方法:动态规划+记忆化搜索
我们可以用 dp[i][j][k] 来表示从索引 i 到 j 范围内值为 k 的方案数,令某个运算符的索引为 n,那么以该索引为分割点,左右两边填上括号,那么整个运算式的值,就为运算符两边为某个值时的方案数之积,那么我们可以写出状态转移方程:
我们可以令每个值的初始值为 -1,当遍历到数组值不为 -1 时,直接返回该数组值,避免重复遍历。
时间复杂度:O(n^2) n 为字符串中数字的个数
空间复杂度:O(n^2)
class Solution {
//创建dp数组
int[][][] dp;
//字符数组
char[] cs;
//四种情况
int[][] conds = new int[][]{{0, 0}, {0, 1}, {1, 0}, {1, 1}};
public int countEval(String s, int result) {
cs = s.toCharArray();
//获取长度
int len = cs.length;
//创建dp数组
dp = new int[len][len][2];
//初始化dp,将所有值赋为-1
for(int i = 0; i < len; ++i){
for(int j = 0; j < len; ++j){
dp[i][j][0] = -1;
dp[i][j][1] = -1;
}
}
return recur(0, len-1, result);
}
//进行dp运算
public int recur(int start, int end, int result){
//索引相等
if(start == end){
return cs[start] - '0' == result ? 1 : 0;
}
//防止重复遍历
if(dp[start][end][result] != -1){
return dp[start][end][result];
}
//记录方案数
int sum = 0;
//遍历
for(int i = start+1; i < end; i+=2){
//遍历四种情况
for(int[] con: conds){
//进行位运算
if(calc(con[0], con[1], cs[i]) == result){
sum += recur(start, i-1, con[0]) * recur(i+1, end, con[1]);
}
}
}
//赋值
dp[start][end][result] = sum;
return sum;
}
//进行位运算
public int calc(int a, int b, char c){
//与运算
if(c == '&'){
return a & b;
}
//或运算
if(c == '|'){
return a | b;
}
//异或运算
return a ^ b;
}
}
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/boolean-evaluation-lcci