关于java:检查三个布尔值中是否至少有两个是真的

Check if at least two out of three booleans are true

一位面试官最近问我这个问题:给定三个布尔变量A、B和C,如果三个变量中至少有两个是真的,则返回真。

我的解决方案如下:

1
2
3
4
5
6
7
8
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    else{
        return false;
    }
}

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


而不是写作:

1
2
3
4
5
if (someExpression) {
    return true;
} else {
    return false;
}

写:

1
return someExpression;

至于表达式本身,类似于:

1
2
3
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a ? (b || c) : (b && c);
}

或者这个(你觉得哪个更容易掌握):

1
2
3
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a && (b || c) || (b && c);
}

它只测试一次ab,最多测试一次c

工具书类

  • JLS 15.25条件运算符?:


只是为了使用XOR来回答一个相对直接的问题…

1
return a ^ b ? c : a


为什么不按字面意思执行呢?:)

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

在C语言中,您只需编写a+b+c >= 2!!a+!!b+!!c >= 2,以确保非常安全。

为了响应TofuBeer对Java字节码的比较,这里有一个简单的性能测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
class Main
{
    static boolean majorityDEAD(boolean a,boolean b,boolean c)
    {
        return a;
    }

    static boolean majority1(boolean a,boolean b,boolean c)
    {
        return a&&b || b&&c || a&&c;
    }

    static boolean majority2(boolean a,boolean b,boolean c)
    {
        return a ? b||c : b&&c;
    }

    static boolean majority3(boolean a,boolean b,boolean c)
    {
        return a&b | b&c | c&a;
    }

    static boolean majority4(boolean a,boolean b,boolean c)
    {
        return (a?1:0)+(b?1:0)+(c?1:0) >= 2;
    }

    static int loop1(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority1(data[i], data[j], data[k])?1:0;
                sum += majority1(data[i], data[k], data[j])?1:0;
                sum += majority1(data[j], data[k], data[i])?1:0;
                sum += majority1(data[j], data[i], data[k])?1:0;
                sum += majority1(data[k], data[i], data[j])?1:0;
                sum += majority1(data[k], data[j], data[i])?1:0;
            }
        }
        return sum;
    }

    static int loop2(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority2(data[i], data[j], data[k])?1:0;
                sum += majority2(data[i], data[k], data[j])?1:0;
                sum += majority2(data[j], data[k], data[i])?1:0;
                sum += majority2(data[j], data[i], data[k])?1:0;
                sum += majority2(data[k], data[i], data[j])?1:0;
                sum += majority2(data[k], data[j], data[i])?1:0;
            }
        }
        return sum;
    }

    static int loop3(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority3(data[i], data[j], data[k])?1:0;
                sum += majority3(data[i], data[k], data[j])?1:0;
                sum += majority3(data[j], data[k], data[i])?1:0;
                sum += majority3(data[j], data[i], data[k])?1:0;
                sum += majority3(data[k], data[i], data[j])?1:0;
                sum += majority3(data[k], data[j], data[i])?1:0;
            }
        }
        return sum;
    }

    static int loop4(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority4(data[i], data[j], data[k])?1:0;
                sum += majority4(data[i], data[k], data[j])?1:0;
                sum += majority4(data[j], data[k], data[i])?1:0;
                sum += majority4(data[j], data[i], data[k])?1:0;
                sum += majority4(data[k], data[i], data[j])?1:0;
                sum += majority4(data[k], data[j], data[i])?1:0;
            }
        }
        return sum;
    }

    static int loopDEAD(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majorityDEAD(data[i], data[j], data[k])?1:0;
                sum += majorityDEAD(data[i], data[k], data[j])?1:0;
                sum += majorityDEAD(data[j], data[k], data[i])?1:0;
                sum += majorityDEAD(data[j], data[i], data[k])?1:0;
                sum += majorityDEAD(data[k], data[i], data[j])?1:0;
                sum += majorityDEAD(data[k], data[j], data[i])?1:0;
            }
        }
        return sum;
    }

    static void work()
    {
        boolean [] data = new boolean [10000];
        java.util.Random r = new java.util.Random(0);
        for(int i=0;i<data.length;i++)
            data[i] = r.nextInt(2) > 0;
        long t0,t1,t2,t3,t4,tDEAD;
        int sz1 = 100;
        int sz2 = 100;
        int sum = 0;

        t0 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop1(data, i, sz1, sz2);

        t1 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop2(data, i, sz1, sz2);

        t2 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop3(data, i, sz1, sz2);

        t3 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop4(data, i, sz1, sz2);

        t4 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loopDEAD(data, i, sz1, sz2);

        tDEAD = System.currentTimeMillis();

        System.out.println("a&&b || b&&c || a&&c :" + (t1-t0) +" ms");
        System.out.println("   a ? b||c : b&&c   :" + (t2-t1) +" ms");
        System.out.println("   a&b | b&c | c&a   :" + (t3-t2) +" ms");
        System.out.println("   a + b + c >= 2    :" + (t4-t3) +" ms");
        System.out.println("       DEAD          :" + (tDEAD-t4) +" ms");
        System.out.println("sum:"+sum);
    }

    public static void main(String[] args) throws InterruptedException
    {
        while(true)
        {
            work();
            Thread.sleep(1000);
        }
    }
}

在我的机器上打印以下内容(在英特尔核心2上运行Ubuntu + SunJava1.60Y15-B03与热点服务器VM(141-B02,混合模式)):

第一次和第二次迭代:

1
2
3
4
5
6
a&&b || b&&c || a&&c : 1740 ms
   a ? b||c : b&&c   : 1690 ms
   a&b | b&c | c&a   : 835 ms
   a + b + c >= 2    : 348 ms
       DEAD          : 169 ms
sum: 1472612418

后期迭代:

1
2
3
4
5
a&&b || b&&c || a&&c : 1638 ms
   a ? b||c : b&&c   : 1612 ms
   a&b | b&c | c&a   : 779 ms
   a + b + c >= 2    : 905 ms
       DEAD          : 221 ms

我想知道,Java VM会随着时间的推移而降低性能(A+B+C>=2)。

这里,如果我用一个EDCOX1×5 VM交换机运行Java,将会发生什么:

1
2
3
4
5
a&&b || b&&c || a&&c : 4034 ms
   a ? b||c : b&&c   : 2215 ms
   a&b | b&c | c&a   : 1347 ms
   a + b + c >= 2    : 6589 ms
       DEAD          : 1016 ms

奥秘…

如果我在GNU-Java解释器中运行它,它会慢100倍,但是EDCOX1×6版本则获胜。

从运行OS X的最新代码的ToSubeer获得的结果:

1
2
3
4
5
a&&b || b&&c || a&&c : 1358 ms
   a ? b||c : b&&c   : 1187 ms
   a&b | b&c | c&a   : 410 ms
   a + b + c >= 2    : 602 ms
       DEAD          : 161 ms

Mac Java1.602626-B03-33-11A511的Paul Wagland结果

1
2
3
4
5
6
7
a&&b || b&&c || a&&c : 394 ms
   a ? b||c : b&&c   : 435 ms
   a&b | b&c | c&a   : 420 ms
   a + b + c >= 2    : 640 ms
   a ^ b ? c : a     : 571 ms
   a != b ? c : a    : 487 ms
       DEAD          : 170 ms


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

1
2
3
4
5
6
      | C | !C
------|---|----
 A  B | 1 | 1
 A !B | 1 | 0
!A !B | 0 | 0
!A  B | 1 | 0

从中可以推断,第一行需要一组润滑油,第一列需要两组润滑油,从而获得多基因润滑油的最佳解决方案:

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


目标应该是可读性。阅读代码的人必须立即理解您的意图。这是我的解决方案。

1
2
3
4
5
6
int howManyBooleansAreTrue =
      (a ? 1 : 0)
    + (b ? 1 : 0)
    + (c ? 1 : 0);

return howManyBooleansAreTrue >= 2;


1
return (a==b) ? a : c;

说明:

如果a==b都是真的或都是假的。如果两者都是真的,我们就找到了两个真正的布尔值,并且可以返回真值(通过返回a)。如果两者都是错误的,即使c是正确的,也不能有两个真正的布尔值,因此我们返回错误(通过返回a)。这就是(a==b) ? a部分。那么: c呢?如果a==b是假的,那么ab中的一个必须是真的,所以我们找到了第一个真正的布尔值,唯一重要的是,如果c也是真的,那么我们返回c作为答案。


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

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

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


这是一种测试驱动的通用方法。不是像目前为止提供的大多数解决方案那样"高效",而是清晰的、经过测试的、有效的和通用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
    }
}


总结一下。它被称为布尔代数是有原因的:

1
2
3
4
5
6
7
  0 x 0 = 0
  1 x 0 = 0
  1 x 1 = 1

  0 + 0 = 0
  1 + 0 = 1
  1 + 1 = 0 (+ carry)

如果你看这里的真值表,你会发现乘法是布尔的,简单地说加法就是异或。

要回答您的问题:

1
return (a + b + c) >= 2


1
2
3
4
boolean atLeastTwo(boolean a, boolean b, boolean c)
{
  return ((a && b) || (b && c) || (a && c));
}

这真的取决于你所说的"改进"是什么意思:

Clearer?

1
2
3
4
boolean twoOrMoreAreTrue(boolean a, boolean b, boolean c)
{
    return (a && b) || (a && c) || (b && c);
}

Terser?

1
2
3
4
boolean moreThanTwo(boolean a, boolean b, boolean c)
{
    return a == b ? a : c;
}

更一般?

1
2
3
4
5
6
7
8
9
10
11
12
13
boolean moreThanXTrue(int x, boolean[] bs)
{
    int count = 0;

    for(boolean b : bs)
    {
        count += b ? 1 : 0;

        if(count > x) return true;
    }

    return false;
}

更具伸缩性?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
boolean moreThanXTrue(int x, boolean[] bs)
{
    int count = 0;

    for(int i < 0; i < bs.length; i++)
    {
        count += bs[i] ? 1 : 0;

        if(count > x) return true;

        int needed = x - count;
        int remaining = bs.length - i;

        if(needed >= remaining) return false;
    }

    return false;
}

更快?

1
// Only profiling can answer this.

哪一个"改进"在很大程度上取决于形势。


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

创建布尔型数据库values

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

创建地图,减少功能:

编辑:我喜欢curtaindog关于将map/reduce应用于泛型列表的回答,所以这里有一个map函数,它接受一个回调,该回调决定是否应该计算一个值。

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}

运行图/减少:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}


另一个直接代码示例:

1
2
3
4
5
int  n = 0;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 2);

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

补遗

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

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

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


在这里(到目前为止)回答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class X
{
    static boolean a(final boolean a, final boolean b, final boolean c)
    {
    return ((a && b) || (b && c) || (a && c));
    }

    static boolean b(final boolean a, final boolean b, final boolean c)
    {
    return a ? (b || c) : (b && c);
    }

    static boolean c(final boolean a, final boolean b, final boolean c)
    {
    return ((a & b) | (b & c) | (c & a));
    }

    static boolean d(final boolean a, final boolean b, final boolean c)
    {
    return ((a?1:0)+(b?1:0)+(c?1:0) >= 2);
    }
}

并通过反编译器运行它们(javap-c x>results.txt):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
Compiled from"X.java"
public class X extends java.lang.Object{
public X();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

static boolean a(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    8
   4:   iload_1
   5:   ifne    24
   8:   iload_1
   9:   ifeq    16
   12:  iload_2
   13:  ifne    24
   16:  iload_0
   17:  ifeq    28
   20:  iload_2
   21:  ifeq    28
   24:  iconst_1
   25:  goto    29
   28:  iconst_0
   29:  ireturn

static boolean b(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    20
   4:   iload_1
   5:   ifne    12
   8:   iload_2
   9:   ifeq    16
   12:  iconst_1
   13:  goto    33
   16:  iconst_0
   17:  goto    33
   20:  iload_1
   21:  ifeq    32
   24:  iload_2
   25:  ifeq    32
   28:  iconst_1
   29:  goto    33
   32:  iconst_0
   33:  ireturn

static boolean c(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   iload_1
   2:   iand
   3:   iload_1
   4:   iload_2
   5:   iand
   6:   ior
   7:   iload_2
   8:   iload_0
   9:   iand
   10:  ior
   11:  ireturn

static boolean d(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    8
   4:   iconst_1
   5:   goto    9
   8:   iconst_0
   9:   iload_1
   10:  ifeq    17
   13:  iconst_1
   14:  goto    18
   17:  iconst_0
   18:  iadd
   19:  iload_2
   20:  ifeq    27
   23:  iconst_1
   24:  goto    28
   27:  iconst_0
   28:  iadd
   29:  iconst_2
   30:  if_icmplt   37
   33:  iconst_1
   34:  goto    38
   37:  iconst_0
   38:  ireturn
}

你能看到吗?:比原版稍好一点。最好的是避免完全分支的那个。从指令较少(在大多数情况下)的角度来看,这很好,对CPU的分支预测部分更好,因为分支预测中的错误猜测可能导致CPU停止。

我想说最有效的一个是从月亮阴影整体。它平均使用最少的指令,并减少了CPU中管道暂停的可能性。

要100%确定,您需要找出每个指令的成本(以CPU周期为单位),但不幸的是,这些成本并不容易获得(您必须查看热点的源代码,然后查看CPU供应商对每个生成的指令所用时间的说明)。

有关代码的运行时分析,请参阅Rotsor更新的答案。


还有另一种方法,但不是很好:

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

Booleanhashcode值固定为1231(真)和1237(假),因此可以使用<= 3699


最明显的改进是:

1
2
3
4
5
6
7
// There is no point in an else if you already returned.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    return false;
}

然后

1
2
3
4
// There is no point in an if(true) return true otherwise return false.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return ((a && b) || (b && c) || (a && c));
}

但这些改进是微不足道的。


我不喜欢三元(最上面的答案是return a ? (b || c) : (b && c);),我想我没看到有人提到过。它是这样写的:

1
2
3
4
5
6
7
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if (a) {
        return b||c;
    }
    else {
        return b&&C;
    }


在克洛杰里:

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

用途:

1
(at-least 2 true false true)


我们可以将bools转换为整数并执行以下简单检查:

1
(int(a) + int(b) + int(c)) >= 2

我想我还没有看到这个解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

它的优点是一旦达到你要找的数字,它就会断开。如果这是"1000000个值中至少有2个是真的",前两个值实际上是真的,那么它应该比一些更"正常"的解更快。


由于没有规定如何改进代码,我将努力改进代码,使其更有趣。我的解决方案是:

1
2
3
4
5
6
7
8
9
10
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;
}

如果有人想知道这段代码是否有效,可以使用相同的逻辑进行简化:

1
2
3
4
5
6
7
8
9
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;

}

这可以进一步归结为:

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

但现在不再有趣了。


C解决方案。

1
2
3
int two(int a, int b, int c) {
  return !a + !b + !c < 2;
}

或者您可能更喜欢:

1
2
3
int two(int a, int b, int c) {
  return !!a + !!b + !!c >= 2;
}

1
2
3
4
5
6
Function ReturnTrueIfTwoIsTrue(bool val1, val2, val3))
{
     return (System.Convert.ToInt16(val1) +
             System.Convert.ToInt16(val2) +
             System.Convert.ToInt16(val3)) > 1;
}

这么做的方法太多了…


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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}


1
return 1 << $a << $b << $c >= 1 << 2;


作为@tofubeer tofubeer优秀文章的补充,请考虑@pdox pdox的答案:

1
2
3
4
static boolean five(final boolean a, final boolean b, final boolean c)
{
    return a == b ? a : c;
}

还可以考虑"javap-c"给出的反汇编版本:

1
2
3
4
5
6
7
8
9
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的答案编译的字节代码比以前的任何答案都少。它的执行时间与其他时间相比如何?

1
2
3
4
5
one                5242 ms
two                6318 ms
three (moonshadow) 3806 ms
four               7192 ms
five  (pdox)       3650 ms

至少在我的电脑上,pdox的答案比@moonshadow moonshadow的答案略快,使pdox成为最快的整体(在我的HP/Intel笔记本电脑上)。


最简单的方法(IMO)不容易混淆和阅读:

1
2
3
// Three booleans, check if two or more are true

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


通过真值表计算:

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


这种类型的阅读效果更好:

1
2
3
4
5
6
if (a) {
    return b || c;
}
else {
    return b && c;
}

在C:

1
return !!a + !!b + !!c >= 2;


露比:

[a, b, c].count { |x| x } >= 2

它可以在javavm上的jruby中运行。;-)


他可能没有寻找任何复杂的东西,比如位比较运算符(通常不复杂,但是有布尔值,使用位比较运算符是非常奇怪的),或者一些非常迂回的东西,比如转换为int并求和。

解决这一问题最直接和自然的方法是使用如下表达式:

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

如果你愿意的话,把它放在一个函数中,但是它并不复杂。该解决方案在逻辑上简洁高效。


应该是:

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

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

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

当我看到这个问题时,我的第一个想法是:

1
2
3
4
5
6
7
8
int count=0;
if (a)
    ++count;
if (b)
    ++count;
if (c)
    ++count;
return count>=2;

在看到其他帖子后,我承认

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

更优雅。我想知道相对的运行时间是什么。

无论如何,我认为这种解决方案比

1
return a&b | b&c | a&c;

因为品种更容易扩展。如果稍后我们添加第四个必须测试的变量呢?如果变量的数量是在运行时确定的,并且我们被传递一个未知大小的布尔数组,会怎么样?依赖于计数的解决方案比依赖于列出所有可能组合的解决方案更容易扩展。此外,当列出所有可能的组合时,我怀疑犯错误要容易得多。比如试着为"4中的任意3"编写代码,并确保您不会错过任何代码,也不会复制任何代码。现在用"任意5/7"试试。


我找到了这个解决方案。

1
2
3
4
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    bool result = !(a ^ b ^ c) && !(!a & !b & !c) || (a & b & c);
    return result;
}

三元操作符可以让书呆子的汁液流动,但它们可能会令人困惑(使代码不易维护,从而增加了bug注入的可能性)。杰夫·阿特伍德在这里说得很好:

It's a perfect example of trading off
an utterly meaningless one time
write-time savings against dozens of
read-time comprehension penalties-- It
Makes Me Think.

为了避免使用三元运算符,我创建了以下函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
function atLeastTwoTrue($a, $b, $c) {
        $count = 0;

        if ($a) { $count++; }
        if ($b) { $count++; }
        if ($c) { $count++; }

        if ($count >= 2) {
                return true;
        } else {
                return false;
        }
}

这和其他一些解决方案一样酷吗?不,更容易理解吗?对。这会导致可维护性更强、错误代码更少吗?对。


EDCOX1×4×-Java如何使用三个比较而不是OP的六。

错了,我应该早点检查。


对这个问题的最佳答案应该是"作为一名员工,我写它是很重要的,这样我的意思就清晰了,同时在绩效需要的地方保持效率。"下面是我写它的方式:

1
2
3
function atLeastTwoAreTrue(a, b, c) {
    return (a && b) || (b && c) || (a && c);
}

实际上,这个测试是如此的做作,以至于如果你用一个简单的注释来适应它,那么写一个最快、最神秘的方法是完全可以接受的。但是,总的来说,在这个一行程序的世界中,我们需要在这个世界上有更多可读的代码。-)


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

1
2
3
4
5
6
7
8
9
10
     static boolean trueBooleans (int howMany,boolean ... bools)
     {
      int total = 0;

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


      return false;
    }

在我编写Java的拙劣意见中,容易处理意外变化和重复代码比简洁(脚本语言域)或快速程序更重要。


仅供参考,这只是一个完整的加法器的执行位。在硬件方面,您可以使用逻辑工作来根据不同的布尔表达式来确定最佳电路。我想传统的XOR解决方案要比海报所展示的不那么简洁的表达更费劲。


让这三个布尔值为a、b和c…。

您可以使用k-map并使用布尔表达式…

在这种情况下,布尔表达式将是a(b+c)+c

或者如果((a&;&;(b_c))c){回归真实;}其他的返回错误;


这个问题的非简化解决方案是:

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

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

1
bc + ab + ac

我们可以通过在A'BC和ABC的造币厂使用独家或联合使用ABC和AB'C的造币厂来进一步减少这一点:

1
b(a ^ c) + ac

当然,这个问题更多的是关于你如何解决问题/思考,而不是你实际的编码能力。

一个稍微简洁的版本可以是

return ((a ^ b) && (b ^ c)) ^ b

但是就像以前的海报上说的,如果我在我正在研究的任何代码中看到这个,就会有人听到了。:)


所提出问题中的2和3肯定是神奇的数字。"正确"的答案取决于面试官是否试图掌握布尔逻辑(我不认为PDOX的答案在这方面是最好的)或者你对架构问题的理解。

我倾向于使用一个map-reduce解决方案,它可以接受任何具有任意条件的列表。


x=或(a+b,c)

A BC X

1 1 0 0

0 0 1 1

0 1 1 1


如果目标是为三个操作数返回三个值中的两个,则算术和迭代方法往往相对无效。在许多CPU架构中,一个好的形式是"返回((A&B)&C)(A&B);"。这需要四个布尔运算。在单累加器机器上(在小型嵌入式系统中很常见),每字节总有七条指令。"RETURN(A&B)(A&C)(B&C);"形式可能看起来更好,但它需要五个布尔运算,或者一台累加器机器上每字节九个指令。

顺便说一下,在CMOS逻辑中,计算"三取二"需要12个晶体管(相比之下,一个反相器需要两个,一个两输入NAND或不需要四个,一个三输入NAND或不需要六个)。


有一件事我没有看到其他人指出,在求职面试的"请给我写一些代码"部分,一个标准的做法是说"你能改进一下吗?"或者"你对此完全满意"或者"这是尽可能优化的吗?"当你说你完成了。有可能你听到"你会怎样改进它",因为"这可能会得到改进;如何改进?".在这种情况下,将if(x) return true; else return false;习惯用法更改为"仅return x"是一种改进,但要注意,有时他们只是想了解您对问题的反应。我听说有些面试官会坚持认为完美代码中有一个缺陷,只是为了看看你如何处理它。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int count=0;

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if (a)
        count++;
    if (b)
        count++;
    if (c)
        count++;

    if (count>1)
        return true;
    else
        return false;
}

在C中,从我的头顶开始:

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

应该很快。

呼叫如下:

1
lol( 2, true, true, false );

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


现在用Java 8,我真的很喜欢这样的事情:

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


使用Java 8的流功能,对任意数量的任意数量的布尔值采取另一种方法。如果在处理所有元素之前流达到极限,则流会短路:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static boolean atLeastTrue(int amount, Boolean ... booleans) {
    return Stream.of(booleans).filter(b -> b).limit(amount).count() == amount;
}

public static void main(String[] args){
    System.out.println("1,2:" + atLeastTrue(1, true, false, true));
    System.out.println("1,1:" + atLeastTrue(1, false, true));
    System.out.println("1,0:" + atLeastTrue(1, false));
    System.out.println("1,1:" + atLeastTrue(1, true, false));
    System.out.println("2,3:" + atLeastTrue(2, true, false, true, true));
    System.out.println("3,2:" + atLeastTrue(3, true, false, true, false));
    System.out.println("3,3:" + atLeastTrue(3, true, true, true, false));
}

输出:

1
2
3
4
5
6
7
1,2: true
1,1: true
1,0: false
1,1: true
2,3: true
3,2: false
3,3: true

这个怎么样:

1
(a - b) ? c : a


丙:

1
if (!!a + !!b + !!c >= 2)

在我看来,三分之三是相当任意的数字,函数应该使用任意的数字。为了回答这个问题,我写了一个函数,如果数组中的x是真的,就可以算出这个函数。

1
2
3
bool istrue ( int x, bool[] list)
    y = count true in list
    return y >= x


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

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

我只是给你一个选择。


使用三元运算符解决问题的最简单形式是:

1
return a ? (b ? true : c) : (b ? c : false);

您可能还希望通过使用需求的双重否定来投资寻找解决方案,也就是说,您需要满足条件,而不是至少两个真值,最多一个假值。


函数ko返回答案:

1
2
3
4
5
6
7
8
9
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;
}


1
2
3
4
5
6
7
public static boolean atLeast(int atLeastToBeTrue, boolean...bools){
    int booleansTrue = 0;
    for(boolean tmp : bools){
        booleansTrue += tmp ? 1 : 0;
    }
    return booleansTrue >= atLeastToBeTrue;
}

你可以从varargsa.k.a boolean[]中选择你想要真实的at least个数:


另一个:

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

1
2
3
4
5
6
7
8
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);
}


我相信使用普通的布尔运算符(a b)&;&;(b c)是很好的,而且更简单。

你可以把这三个字母中的任何一个换成另外两个字母中的任何一个,它仍然是相同的表达式。


我认为最简单的解决方案是:

返回(A&B)C;


我的第一个想法是

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

但为了便于阅读,我喜欢你们建议的A+B+C>=2解决方案。