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

我的解决方案如下:

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

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


当前回答

不是在性能的上下文中,而是在良好的代码(可扩展和可读的代码,可以重用)

     static boolean trueBooleans (int howMany,boolean ... bools)
     {
      int total = 0;

      for (boolean b:bools)
        if (b && (++total == howMany)) return true;


      return false;
    }

在我看来,在编写Java时,易于处理意外更改和无重复代码比简洁(脚本语言领域)或快速程序更重要。

其他回答

下面是使用map/reduce的另一个实现。在分布式环境中,这可以很好地扩展到数十亿布尔值©。使用MongoDB:

创建数据库的布尔值:

db.values.insert({value: true});
db.values.insert({value: false});
db.values.insert({value: true});

创建map, reduce函数:

编辑:我喜欢CurtainDog的回答有映射/减少适用于泛型列表,所以这里有一个地图函数,它接受一个回调,决定一个值是否应该被计数。

var mapper = function(shouldInclude) {
    return function() {
        emit(null, shouldInclude(this) ? 1 : 0);
    };
}

var reducer = function(key, values) {
    var sum = 0;
    for(var i = 0; i < values.length; i++) {
        sum += values[i];
    }
    return sum;
}

运行map / reduce:

var result = db.values.mapReduce(mapper(isTrue), reducer).result;

containsMinimum(2, result); // true
containsMinimum(1, result); // false


function isTrue(object) {
    return object.value == true;
}

function containsMinimum(count, resultDoc) {
    var record = db[resultDoc].find().next();
    return record.value >= count;
}

它应该是:

(a || b && c) && (b || c && a)

此外,如果true自动转换为1,false自动转换为0:

(a + b*c) * (b + c*a) > 0

目前的Java 8,我真的更喜欢这样的东西:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return Stream.of(a, b, c).filter(active -> active).count() >= 2;
}

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

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

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

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

函数ko返回答案:

static int ho(bool a)
{
    return a ? 1 : 0;
}

static bool ko(bool a, bool b, bool c)
{
    return ho(a) + ho(b) + ho(c) >= 2 ? true : false;
}