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

我的解决方案如下:

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

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


当前回答

下面是一个测试驱动的通用方法。虽然不像目前提供的大多数解决方案那样“高效”,但是清晰、经过测试、有效且通用。

public class CountBooleansTest extends TestCase {
    public void testThreeFalse() throws Exception {
        assertFalse(atLeastTwoOutOfThree(false, false, false));
    }

    public void testThreeTrue() throws Exception {
        assertTrue(atLeastTwoOutOfThree(true, true, true));
    }

    public void testOnes() throws Exception {
        assertFalse(atLeastTwoOutOfThree(true, false, false));
        assertFalse(atLeastTwoOutOfThree(false, true, false));
        assertFalse(atLeastTwoOutOfThree(false, false, true));
    }

    public void testTwos() throws Exception {
        assertTrue(atLeastTwoOutOfThree(false, true, true));
        assertTrue(atLeastTwoOutOfThree(true, false, true));
        assertTrue(atLeastTwoOutOfThree(true, true, false));
    }

    private static boolean atLeastTwoOutOfThree(boolean b, boolean c, boolean d) {
        return countBooleans(b, c, d) >= 2;
    }

    private static int countBooleans(boolean... bs) {
        int count = 0;
        for (boolean b : bs)
            if (b)
                count++;
        return count;
    }
}

其他回答

这样读起来更好:

if (a) {
    return b || c;
} 
else {
    return b && c;
}

还有一种不太好的方法:

return (Boolean.valueOf(a).hashCode() + Boolean.valueOf(b).hashCode() + Boolean.valueOf(c).hashCode()) < 3705);

布尔哈希码值固定为true为1231,false为1237,因此同样可以使用<= 3699

您不需要使用运算符的短路形式。

返回(a & b) | (b & c) | (c & a);

它执行与您的版本相同数量的逻辑操作,但是完全没有分支。

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

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个是真的”,而前两个值实际上是真的,那么它应该比一些更“正常”的解更快。

而不是写:

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条件运算符?: