本文翻譯自:Check if at least two out of three booleans are true
An interviewer recently asked me this question: given three boolean variables, a, b, and c, return true if at least two out of the three are true.
一位采訪者最近問我這個問題:給定三個布爾變量a,b和c,如果三個中至少有兩個為真,則傳回true。My solution follows:
我的解決方案是:boolean atLeastTwo(boolean a, boolean b, boolean c) {
if ((a && b) || (b && c) || (a && c)) {
return true;
}
else{
return false;
}
}
He said that this can be improved further, but how?
他說這可以進一步改善,但如何?#1樓
參考:https://stackoom.com/question/CuEA/檢查三個布爾值中是否至少有兩個是真的
#2樓
Rather than writing:
而不是寫:if (someExpression) {
return true;
} else {
return false;
}
Write:
寫:return someExpression;
As for the expression itself, something like this:
至于表達本身,這樣的事情:boolean atLeastTwo(boolean a, boolean b, boolean c) {
return a ? (b || c) : (b && c);
}
or this (whichever you find easier to grasp):
或者這個(無論你發現哪個更容易掌握):boolean atLeastTwo(boolean a, boolean b, boolean c) {
return a && (b || c) || (b && c);
}
It tests
a
and
b
exactly once, and
c
at most once.
它隻測試a
和 b
一次,最多 c
次測試一次。 References 參考
- JLS 15.25 Conditional Operator ? JLS 15.25條件運算符? : :
#3樓
Why not implement it literally?
為什麼不按字面意思實作呢?:)
:)(a?1:0)+(b?1:0)+(c?1:0) >= 2
In C you could just write
a+b+c >= 2
(or
!!a+!!b+!!c >= 2
to be very safe).
在C中你可以寫a+b+c >= 2
(或 !!a+!!b+!!c >= 2
非常安全)。 In response to TofuBeer 's comparison of java bytecode, here is a simple performance test:
為了回應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);
}
}
}
This prints the following on my machine (running Ubuntu on Intel Core 2 + sun java 1.6.0_15-b03 with HotSpot Server VM (14.1-b02, mixed mode)):
這将在我的機器上列印以下内容(使用HotSpot Server VM(14.1-b02,混合模式)在Intel Core 2 + sun java 1.6.0_15-b03上運作Ubuntu):First and second iterations:
第一次和第二次疊代: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
Later iterations:
後來的疊代: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
I wonder, what could java VM do that degrades performance over time for (a + b + c >= 2) case.
我想知道,對于(a + b + c> = 2)情況,java VM可以做什麼會降低性能随時間的變化。And here is what happens if I run java with a
-client
VM switch:
如果我使用-client
VM開關運作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
Mystery...
神秘...And if I run it in GNU Java Interpreter , it gets almost 100 times slower, but the
a&&b || b&&c || a&&c
如果我在GNU Java Interpreter中運作它,它會慢幾百倍,但是 a&&b || b&&c || a&&c
a&&b || b&&c || a&&c
a&&b || b&&c || a&&c
version wins then.
然後a&&b || b&&c || a&&c
版本獲勝。 Results from Tofubeer with the latest code running OS X:
使用運作OS X的最新代碼從Tofubeer獲得的結果: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
Results from Paul Wagland with a Mac Java 1.6.0_26-b03-383-11A511
來自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
#4樓
The most obvious set of improvements are:
最明顯的改進是:// 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;
}
and then
然後// 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));
}
But those improvements are minor.
但這些改進很小。#5樓
You don't need to use the short circuiting forms of the operators.
您不需要使用運算符的短路形式。return (a & b) | (b & c) | (c & a);
This performs the same number of logic operations as your version, however is completely branchless.
這将執行與您的版本相同數量的邏輯操作,但是完全無分支。#6樓
Readability should be the goal.
可讀性應該是目标。Someone who reads the code must understand your intent immediately.
閱讀代碼的人必須立即了解您的意圖。So here is my solution.
是以這是我的解決方案。int howManyBooleansAreTrue =
(a ? 1 : 0)
+ (b ? 1 : 0)
+ (c ? 1 : 0);
return howManyBooleansAreTrue >= 2;