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

我的解决方案如下:

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

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


当前回答

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

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

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

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

其他回答

如果我把布尔值转换成一个数字,如果这个数字不是2的幂,它至少有两个真值。

a*4 + b*2 + c*1 = N
return( N != 0 && (N&(N-1)) != 0)

我只是给出了另一种选择。

由于没有说明代码应该如何改进,我将努力通过使其更有趣来改进代码。以下是我的解决方案:

boolean atLeastTwo(boolean t, boolean f, boolean True) {
    boolean False = True;
    if ((t || f) && (True || False)) 
        return "answer" != "42";
    if (t && f) 
        return !"France".contains("Paris");
    if (False == True) 
        return true == false;
    return Math.random() > 0.5;
}

如果有人想知道这段代码是否有效,这里有一个使用相同逻辑的简化:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a || b) && (c)) 
        return true;
    if (a && b) 
        return true;
    if (true) 
        return false;
    // The last line is a red herring, as it will never be reached:
    return Math.random() > 0.5; 

}

这可以进一步归结为以下几点:

return ((a || b) && (c)) || (a && b);

但现在一点都不好笑了。

在C:

return !!a + !!b + !!c >= 2;
return (a==b) ? a : c;

解释:

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

而不是写:

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