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

我的解决方案如下:

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

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


当前回答

问题中的2和3显然是神奇的数字。“正确”的答案将取决于面试官是否试图了解你对布尔逻辑的理解(我不认为pdox的答案在这方面是最好的)或你对架构问题的理解。

我倾向于使用映射减少解决方案,它将接受任何类型的列表和任何任意条件。

其他回答

作为@TofuBeer TofuBeer精彩帖子的补充,考虑@pdox pdox的回答:

static boolean five(final boolean a, final boolean b, final boolean c)
{
    return a == b ? a : c;
}

再考虑一下它的分解版本,如"javap -c"所给出的:

static boolean five(boolean, boolean, boolean);
  Code:
    0:    iload_0
    1:    iload_1
    2:    if_icmpne    9
    5:    iload_0
    6:    goto    10
    9:    iload_2
   10:    ireturn

Pdox的答案编译成的字节代码比之前的任何答案都要少。它的执行时间与其他的相比如何?

one                5242 ms
two                6318 ms
three (moonshadow) 3806 ms
four               7192 ms
five  (pdox)       3650 ms

至少在我的电脑上,pdox的回答比@moonshadow moonshadow的回答稍微快一点,使得pdox的回答是最快的(在我的惠普/英特尔笔记本电脑上)。

这个问题的最佳答案应该是:“作为一名员工,我写出来的东西很重要,这样我的意思就能清楚地表达出来,同时又能保持绩效所需的效率。”我是这样写的:

function atLeastTwoAreTrue(a, b, c) {
    return (a && b) || (b && c) || (a && c);
}

在现实中,这个测试是如此的刻意,以至于如果您用一个简单的注释来容纳它,那么编写一个最快、最神秘的方法是完全可以接受的。但是,一般来说,在这个一行代码的世界里,我们需要更多可读的代码。: -)

我想我还没见过这个解决方案:

boolean atLeast(int howMany, boolean[] boolValues) {
  // check params for valid values

  int counter = 0;
  for (boolean b : boolValues) {
    if (b) {
      counter++;

      if (counter == howMany) {
        return true;
      }
    }
  }
  return false;
}

它的优点是一旦达到你要找的数字,它就会崩溃。因此,如果这是“这1,000,000个值中至少有2个是真的”,而前两个值实际上是真的,那么它应该比一些更“正常”的解更快。

三元运算符让人觉得很无聊,但它们也会令人困惑(使代码更难维护,从而增加了注入错误的可能性)。Jeff Attwood说得很好:

这是一个权衡取舍的完美例子 毫无意义的一次 写的时候节省了几十个 阅读时间理解惩罚——它 让我思考。

为了避免三元操作符,我创建了以下函数:

function atLeastTwoTrue($a, $b, $c) {
        $count = 0;

        if ($a) { $count++; }
        if ($b) { $count++; }
        if ($c) { $count++; }

        if ($count >= 2) {
                return true;
        } else {
                return false;
        }
}

这个和其他解一样酷吗?不。这样更容易理解吗?是的。这是否会使代码更具可维护性、bug更少?是的。

总结一下。它被称为布尔代数是有原因的:

  0 x 0 = 0
  1 x 0 = 0
  1 x 1 = 1

  0 + 0 = 0
  1 + 0 = 1
  1 + 1 = 0 (+ carry)

如果你看那里的真值表,你可以看到乘法是布尔和,而简单的加法是异或。

回答你的问题:

return (a + b + c) >= 2