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

我的解决方案如下:

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

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


当前回答

作为@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的回答是最快的(在我的惠普/英特尔笔记本电脑上)。

其他回答

这样读起来更好:

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

在c#中,我首先想到的是:

public bool lol(int minTrue, params bool[] bools)
{
    return bools.Count( ( b ) => b ) >= minTrue;
}

应该很快。

调用应该是这样的:

lol( 2, true, true, false );

这样,您就将规则(两个必须为真)留给调用者,而不是将它们嵌入到方法中。

这类问题可以用卡诺图来解决:

      | C | !C
------|---|----
 A  B | 1 | 1 
 A !B | 1 | 0
!A !B | 0 | 0
!A  B | 1 | 0

由此推断,第一行需要一组,第一列需要两组,得到聚基因润滑剂的最优解:

(C && (A || B)) || (A && B)  <---- first row
       ^
       |
   first column without third case

字面解释适用于所有主要语言:

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

但是我可能会让人们更容易阅读,并且扩展到三个以上——这一点似乎被许多程序员遗忘了:

boolean testBooleans(Array bools)
{
     int minTrue = ceil(bools.length * .5);
     int trueCount = 0;

     for(int i = 0; i < bools.length; i++)
     {
          if(bools[i])
          {
               trueCount++;
          }
     }
     return trueCount >= minTrue;
}

If the goal is to return a bitwise two-out-of-three value for three operands, arithmetic and iterative approaches are apt to be relatively ineffective. On many CPU architectures, a good form would be "return ((a | b) & c) | (a & b);". That takes four boolean operations. On single-accumulator machines (common in small embedded systems) that's apt to take a total of seven instructions per byte. The form "return (a & b) | (a & c) | (b & c);" is perhaps nicer looking, but it would require five boolean operations, or nine instructions per byte on a single-accumulator machine.

顺便提一下,在CMOS逻辑中,计算“不是三选二”需要12个晶体管(相比之下,逆变器需要2个晶体管,双输入NAND或NOR需要4个晶体管,而三输入NAND或NOR需要6个晶体管)。