检查三个布尔值中是否至少有两个为真

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

我的解决方案如下:

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

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

192378 次浏览

而不是写:

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);
}

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

参考文献

为什么不逐字执行呢?:)

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

在C语言中,你可以只写a+b+c >= 2(或者!!a+!!b+!!c >= 2,为了安全起见)。

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

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);
}
}
}

这将在我的机器上打印以下内容(在Intel Core 2 + sun java 1.6.0_15-b03上运行Ubuntu,带有HotSpot Server VM (14.1-b02,混合模式):

第一次和第二次迭代:

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

后来迭代:

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

我想知道,对于(a + b + c >= 2)情况,java虚拟机可以做什么降解性能。

下面是如果我用-client虚拟机开关运行java会发生什么:

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倍,但a&&b || b&&c || a&&c版本会胜出。

在运行OS X的最新代码中,豆腐啤酒的结果:

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

Paul Wagland使用Mac Java 1.6.0_26-b03-383-11A511的结果

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

最明显的改进是:

// 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;
}

然后

// 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));
}

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

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

# EYZ0

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

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

int howManyBooleansAreTrue =
(a ? 1 : 0)
+ (b ? 1 : 0)
+ (c ? 1 : 0);


return howManyBooleansAreTrue >= 2;

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

      | 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

以下是目前为止的答案:

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):

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对代码的运行时分析的更新答案。

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

另一个直接代码的例子:

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的比较使用更快(或更少)的代码。

下面是一个测试驱动的通用方法。虽然不像目前提供的大多数解决方案那样“高效”,但是清晰、经过测试、有效且通用。

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;
}
}

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

创建一个布尔值数据库values:

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

创建map, reduce函数:

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

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;
}

还有一种不太好的方法:

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

Boolean hashcode值固定为true为1231,false为1237,因此同样可以使用<= 3699

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

// Three booleans, check if two or more are true


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

三元运算符让人觉得很无聊,但它们也会令人困惑(使代码更难维护,从而增加了注入错误的可能性)。杰夫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更少?是的。

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

有太多方法可以做到这一点……

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

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

只是为了使用异或来回答一个相对简单的问题……

return a ^ b ? c : a
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);
}

C解。

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

或者你可能更喜欢:

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

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

  0 x 0 = 0
1 x 0 = 0
1 x 1 = 1


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

如果你看那里的真值表,你可以看到乘法是布尔和,而简单的加法是异或。

回答你的问题:

return (a + b + c) >= 2

我的第一个想法是

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

但为了便于阅读,我喜欢你们提出的a+b+c>=2的解决方案

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

一个稍微简洁一点的版本可能是

Return ((a ^ b) &(b ^ c) ^ b

但就像之前的一个帖子说的,如果我在任何我正在编写的代码中看到这个,有人会听到很多。:)

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

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;
}

我想我还没见过这个解决方案:

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;
}

它的优点是一旦达到你要找的数字,它就会崩溃。因此,如果这是“这1,000,000个值中至少有2个是真的”,而前两个值实际上是真的,那么它应该比一些更“正常”的解更快。

在# EYZ0:

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

用法:

(at-least 2 true false true)

X = OR(a+b,c)

a b c X

1 10 0 1

0 0 1 1

0 1 1 1

如果目标是为三个操作数逐位返回三分之二的值,算术和迭代方法往往相对无效。在许多CPU架构上,一个很好的形式是“return ((a | b) &C) | (a &b);”。这需要4个布尔运算。在单累加器机器上(在小型嵌入式系统中常见),每字节可能总共需要7条指令。return (a &B) | (a &C) | (b &C);”可能看起来更好看,但它需要5个布尔操作,或者在单累加器机器上每个字节需要9个指令。

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

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

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

我没有看到其他人指出的一件事是,在求职面试的“请给我写一些代码”部分,当你说你完成了工作时,标准的做法是说“你能改进吗?”或“你对这个完全满意吗?”或“这个是尽可能优化的吗?”有可能你听到的是“你将如何改进”,而不是“这可以改进;如何?”在这种情况下,将if(x) return true; else return false;成语改为return x是一种改进——但要注意,有时他们只是想看看你对问题的反应。我听说有些面试官会坚持认为完美代码中有缺陷,只是想看看你如何应对。

这样读起来更好:

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

这个问题的最佳答案应该是:“作为一名员工,我写出来的东西很重要,这样我的意思就能清楚地表达出来,同时又能保持绩效所需的效率。”我是这样写的:

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

在现实中,这个测试是如此的刻意,以至于如果您用一个简单的注释来容纳它,那么编写一个最快、最神秘的方法是完全可以接受的。但是,一般来说,在这个一行代码的世界里,我们需要更多可读的代码。: -)

通过真值表计算:

return (a & b) | (c & (a ^ b));
return (a==b) ? a : c;

解释:

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

供你参考,这只是一个完整加法器的执行部分。在硬件中,您可以根据不同的布尔表达式使用逻辑工作来确定最佳电路。我猜传统的异或解决方案要比海报上展示的不那么简洁的表达式花费更多的精力。

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

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

应该很快。

调用应该是这样的:

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

这真的取决于你对“改进”的定义:

清晰吗?

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

要简洁?

boolean moreThanTwo(boolean a, boolean b, boolean c)
{
return a == b ? a : c;
}

更一般的?

boolean moreThanXTrue(int x, boolean[] bs)
{
int count = 0;


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


if(count > x) return true;
}


return false;
}

更多的可伸缩的吗?

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;
}

更快呢?

// Only profiling can answer this.

哪一种是“改进”的,很大程度上取决于具体情况。

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;
}

在Ruby中:

# EYZ0

这可以在JavaVM上的JRuby中运行。: -)

问题中的2和3显然是神奇的数字。“正确”的答案将取决于面试官是否试图了解你对布尔逻辑的理解(我不认为pdox的答案在这方面是最好的)或你对架构问题的理解。

我倾向于使用映射减少解决方案,它将接受任何类型的列表和任何任意条件。

我找到了这个解。

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

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

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

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

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

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

不过,无论如何,我认为这种解决办法比那种解决办法要好得多

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

多样性,因为它更容易扩展。如果稍后我们添加第四个必须测试的变量呢?如果变量的数量是在运行时确定的,而我们得到的是一个大小未知的布尔值数组,该怎么办?依赖于计数的解决方案比依赖于列出每个可能组合的解决方案更容易扩展。此外,当列出所有可能的组合时,我怀疑更容易犯错误。比如试着为“4个中的任意3个”写代码,并确保你既没有遗漏任何内容也没有重复任何内容。现在试试“7个中的任意5个”。

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

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

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

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

设三个布尔值为A,B和C....

你可以使用一个k-MAP和一个布尔表达式…

在这种情况下,布尔表达式将是A(B+C) +C

或if(A &&(b || c || c { 返回true; } 其他的 返回false; < / p >

C:

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

它应该是:

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

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

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

在我看来,3 / 3都是非常任意的数,函数应该适用于任意的数。为了回答这个问题,我要写一个函数来计算数组中的x是否为真,例如,

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

在C:

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

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

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

这个问题的非约简解是:

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

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

bc + ab + ac

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

b(a ^ c) + ac

(a||b) && (a||c) - Java怎么样,使用三次比较而不是OP的六次比较。

错,我应该早点检查的。

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

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);

但现在一点都不好笑了。

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

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

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

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

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

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

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

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


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




return false;
}

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

函数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;
}

这个怎么样:

(a - b) ? c : a

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

返回(a &&B) || c;

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

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: true
1,1: true
1,0: false
1,1: true
2,3: true
3,2: false
3,3: true
public static boolean atLeast(int atLeastToBeTrue, boolean...bools){
int booleansTrue = 0;
for(boolean tmp : bools){
booleansTrue += tmp ? 1 : 0;
}
return booleansTrue >= atLeastToBeTrue;
}

你可以选择多少at least你想从varargs a.k.a boolean[]是真的:-)

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

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

另一个:

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

借助于算术运算,这是非常简单的。

boolean a = true;
boolean b = false;
boolean c = true;




// Exactly One boolean value true.
if((a?1:0)+(b?1:0)+(c?1:0)==1) 
return true;
else
return false;


// Exactly 2 boolean value true.
if((a?1:0)+(b?1:0)+(c?1:0)==2)
return true;
else
return false;

这就是你如何增加常量的值来检查有多少布尔值是true

如果你有很多布尔值,操作符重载很容易。

operator fun Boolean.unaryPlus() = if (this) 1 else 0
// ...
if(+bool1 + +bool2 + ... + +boolN > 2) {
// ...
}