Javascript 如何计算将布尔表达式字符串括起来以计算所需结果的方法数
直接从CTCI开始,8.14:给定一个由符号0(false)、1(true)、&(AND)、|(OR)和^(XOR)组成的布尔表达式,以及一个所需的布尔结果值结果,实现一个函数来计算表达式的圆括号数,以使其计算结果 我正在尝试一种蛮力方法来计算每一个可能的组合,如果匹配期望的结果,将其添加到一个数组(组合)并返回结果长度。它似乎适用于大多数表达式,但不适用于给出的第二个示例。我似乎遗漏了什么Javascript 如何计算将布尔表达式字符串括起来以计算所需结果的方法数,javascript,algorithm,recursion,dynamic-programming,boolean-expression,Javascript,Algorithm,Recursion,Dynamic Programming,Boolean Expression,直接从CTCI开始,8.14:给定一个由符号0(false)、1(true)、&(AND)、|(OR)和^(XOR)组成的布尔表达式,以及一个所需的布尔结果值结果,实现一个函数来计算表达式的圆括号数,以使其计算结果 我正在尝试一种蛮力方法来计算每一个可能的组合,如果匹配期望的结果,将其添加到一个数组(组合)并返回结果长度。它似乎适用于大多数表达式,但不适用于给出的第二个示例。我似乎遗漏了什么 function countEval(s, goalBool, combos = []) { /
function countEval(s, goalBool, combos = []) {
// on first call make s into array since theyre easier to work with
if (!(s instanceof Array)) {
// and turn 1s and 0s into their bool equivalent
s = s.split('').map((item) => {
if (item === '1') {
return true;
} else if (item === '0'){
return false;
} else {
return item;
}
});
}
if (s.length === 1 && s[0] === goalBool) {
combos.push(s[0]); // can be anything really
} else {
for (let i = 0; i < s.length - 2; i = i + 2) {
// splice out the next 3 items
const args = s.splice(i, 3);
// pass them to see what they evaluate too
const result = evalHelper(args[0], args[1], args[2]);
// splice that result back in s array
s.splice(i, 0, result);
// pass that array to recurse
countEval(s, goalBool, combos);
// remove said item that was just put in
s.splice(i, 1);
// and reset array for next iteration
s.splice(i, 0, ...args);
}
}
return combos.length;
}
function evalHelper(a, op, b) {
if (op === '|') {
return a || b;
} else if (op === '&') {
return a && b;
} else if (op === '^') {
return a !== b;
}
}
虫子
您的程序未考虑重叠
例子
当s='1 | 1 | 1'
时,请考虑您的程序
在一次深度优先搜索迭代中,您的算法将使约简s=(1 | 1)| 1 | 1
。然后,在同一搜索的更深层次的递归中,您的算法将进行缩减s=(1 | 1)|(1 | 1)
。现在s
已完全减少,因此可以增加组合的长度
在不同的深度优先搜索迭代中,您的算法将首先进行缩减s=1 | 1 |(1 | 1)
。然后,在同一搜索的更深层次的递归中,您的算法将进行缩减s=(1 | 1)|(1 | 1)
。现在s
已完全减少,因此可以增加组合的长度
请注意,对于这两种情况,s
以相同的方式插入括号,因此您的程序不考虑重叠
更好的解决方案
很多时候,当一个问题询问可以做一些事情的方法时,这通常是一个很大的指标,表明动态规划可能是一个潜在的解决方案。这个问题的递归关系有点棘手
我们只需要选择一个“principle”操作符,然后确定左侧和右侧可以计算为true
或false
的方法的数量。然后,基于“principle”操作符和目标布尔值,我们可以推导出表达式可以计算为目标布尔值的方式的数量公式,前提是我们选择的操作符是“principle”操作符
代码
功能方式(expr、res、i、j、缓存、空格){
如果(i==j){
返回parseInt(expr[i])==res?1:0;
}else如果(!([i,j,res]在缓存中)){
var ans=0;
对于(var k=i+1;k
好的。。。但该准则确定的30种方式是什么?打印出来不是很有帮助吗?@Prune啊,是的,谢谢。我这么做了,他们似乎仍然认为是真的。。。这让我觉得我不明白这个问题。但似乎仍然看不出我的算法与给定的解决方案有什么不同:/你的算法已经确定了30种将表达式括起来的方法,但事实上只有10种。让你的程序打印出它找到的30种方法中的每一种,看看它在哪里产生了重复或错误的答案。哦,是的。非常感谢!感谢您的回复,但是我认为您的代码中可能有一个错误,因为当使用字符串0&0&0&1^1
时,countEval('0&0&0&1^0',true)//0
在预期结果为10时返回0…@Afs35mm您能给我一个括号中的0&0&1^0
版本,其计算结果为true
?我想没有。哦。抱歉,一些劣质的意大利面。我的意思是0&0&0&1^1 | 0
,它似乎正确地计算为10,因为。。。谢谢!:)
console.log(countEval('1^0|0|1', false)); // 2, correct
console.log(countEval('0&0&0&1^1|0', true)); // 30, should be 10!?!?!
function ways(expr, res, i, j, cache, spaces) {
if (i == j) {
return parseInt(expr[i]) == res ? 1 : 0;
} else if (!([i, j, res] in cache)) {
var ans = 0;
for (var k = i + 1; k < j; k += 2) {
var op = expr[k];
var leftTrue = ways(expr, 1, i, k - 1, cache);
var leftFalse = ways(expr, 0, i, k - 1, cache);
var rightTrue = ways(expr, 1, k + 1, j, cache);
var rightFalse = ways(expr, 0, k + 1, j, cache);
if (op == '|') {
if (res) {
ans += leftTrue * rightTrue + leftTrue * rightFalse + leftFalse * rightTrue;
} else {
ans += leftFalse * rightFalse;
}
} else if (op == '^') {
if (res) {
ans += leftTrue * rightFalse + leftFalse * rightTrue;
} else {
ans += leftTrue * rightTrue + leftFalse * rightFalse;
}
} else if (op == '&') {
if (res) {
ans += leftTrue * rightTrue;
} else {
ans += leftFalse * rightFalse + leftTrue * rightFalse + leftFalse * rightTrue;
}
}
}
cache[[i, j, res]] = ans;
}
return cache[[i, j, res]];
}
function countEval(expr, res) {
return ways(expr, res ? 1 : 0, 0, expr.length - 1, {});
}