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

我的解决方案如下:

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

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


当前回答

另一个:

return a? b||c : b&&c

其他回答

这个问题的非约简解是:

a'bc + abc' + abc + ab'c

减少使用k - map,可以得到:

bc + ab + ac

可以通过在a'bc和abc' minterms上使用exclusive或,并结合abc和ab'c minterms来进一步减少此值:

b(a ^ c) + ac

另一个直接代码的例子:

int  n = 0;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 2);

显然,这不是最简洁的代码。

齿顶高

另一个(稍微优化的)版本:

int  n = -2;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 0);

这可能会运行得稍微快一点,假设与0的比较将比与2的比较使用更快(或更少)的代码。

function atLeastTwoTrue($a, $b, $c) {

  int count = 0;
  count = (a ? count + 1 : count);
  count = (b ? count + 1 : count);
  count = (c ? count + 1 : count);
  return (count >= 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更少?是的。

在Clojure中:

(defn at-least [n & bools]
  (>= (count (filter true? bools)) n)

用法:

(at-least 2 true false true)