一位面试官最近问了我这样一个问题:给定三个布尔变量a、b和c,如果三个变量中至少有两个为真,则返回true。

我的解决方案如下:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    else{
        return false;
    }
}

他说这还可以进一步改进,但如何改进呢?


当前回答

借助于算术运算,这是非常简单的。

boolean a = true;
boolean b = false;
boolean c = true;


// Exactly One boolean value true.
if((a?1:0)+(b?1:0)+(c?1:0)==1) 
   return true;
else
   return false;

// Exactly 2 boolean value true.
if((a?1:0)+(b?1:0)+(c?1:0)==2) 
   return true;
else
   return false;

这就是你如何增加常数的值来检查有多少布尔值为真

其他回答

return (a==b) ? a : c;

解释:

如果a==b,则两者都为真或都为假。如果两者都为真,我们已经找到了两个真布尔值,并可以返回真(通过返回a)。如果两者都为假,即使c为真,也不可能有两个真布尔值,因此我们返回假(通过返回a)。这是(a==b) ?一个部分。c呢?如果a==b为假,那么a或b中只有一个为真,所以我们找到了第一个真布尔值,剩下的唯一问题是c是否也为真,所以我们返回c作为答案。

If the goal is to return a bitwise two-out-of-three value for three operands, arithmetic and iterative approaches are apt to be relatively ineffective. On many CPU architectures, a good form would be "return ((a | b) & c) | (a & b);". That takes four boolean operations. On single-accumulator machines (common in small embedded systems) that's apt to take a total of seven instructions per byte. The form "return (a & b) | (a & c) | (b & c);" is perhaps nicer looking, but it would require five boolean operations, or nine instructions per byte on a single-accumulator machine.

顺便提一下,在CMOS逻辑中,计算“不是三选二”需要12个晶体管(相比之下,逆变器需要2个晶体管,双输入NAND或NOR需要4个晶体管,而三输入NAND或NOR需要6个晶体管)。

最明显的改进是:

// There is no point in an else if you already returned.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    return false;
}

然后

// There is no point in an if(true) return true otherwise return false.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return ((a && b) || (b && c) || (a && c));
}

但这些改进都是微不足道的。

供你参考,这只是一个完整加法器的执行部分。在硬件中,您可以根据不同的布尔表达式使用逻辑工作来确定最佳电路。我猜传统的异或解决方案要比海报上展示的不那么简洁的表达式花费更多的精力。

在c#中,我首先想到的是:

public bool lol(int minTrue, params bool[] bools)
{
    return bools.Count( ( b ) => b ) >= minTrue;
}

应该很快。

调用应该是这样的:

lol( 2, true, true, false );

这样,您就将规则(两个必须为真)留给调用者,而不是将它们嵌入到方法中。