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

我的解决方案如下:

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

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


当前回答

这类问题可以用卡诺图来解决:

      | C | !C
------|---|----
 A  B | 1 | 1 
 A !B | 1 | 0
!A !B | 0 | 0
!A  B | 1 | 0

由此推断,第一行需要一组,第一列需要两组,得到聚基因润滑剂的最优解:

(C && (A || B)) || (A && B)  <---- first row
       ^
       |
   first column without third case

其他回答

他可能不是在寻找像位比较操作符这样复杂的东西(通常不是复杂的,但使用布尔值,使用位操作符是非常奇怪的),或者像转换为int并对它们求和这样非常迂回的东西。

解决这个问题最直接和自然的方法是用这样的表达式:

a ? (b || c): (b && c)

如果你喜欢,可以把它放到一个函数里,但这并不复杂。该解决方案在逻辑上简洁有效。

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

如果你有很多布尔值,操作符重载很容易。

operator fun Boolean.unaryPlus() = if (this) 1 else 0
// ...
if(+bool1 + +bool2 + ... + +boolN > 2) {
    // ...
}

而不是写:

if (someExpression) {
    return true;
} else {
    return false;
}

写:

return someExpression;

至于表达式本身,是这样的:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a ? (b || c) : (b && c);
}

或者这个(你觉得哪个更容易理解):

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a && (b || c) || (b && c);
}

它只测试a和b一次,c最多测试一次。

参考文献

JLS 15.25条件运算符?:

boolean atLeastTwo(boolean a, boolean b, boolean c) 
{
  return ((a && b) || (b && c) || (a && c));
}