あるインタビュアーが最近私にこの質問をしました:3つのブール変数a、b、およびcが与えられた場合、3つのうち少なくとも2つが真であれば真を返します。
私の解決策は次のとおりです。
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if ((a && b) || (b && c) || (a && c)) {
return true;
}
else{
return false;
}
}
彼はこれがさらに改善されることができると言いました、しかし、どうですか?
書くよりもむしろ:
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);
}
a
とb
は1回だけ、c
は1回までテストされます。
比較的単純な問題に答えるためにXORを使用する目的のためだけに...
return a ^ b ? c : a
文字通りそれを実装しませんか? :)
(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とHotSpot Server VM(14.1-b02、混合モード)でUbuntuを実行している)。
1回目と2回目の繰り返し:
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 VMがそのためにできることがパフォーマンスを低下させるのではないでしょうか。
-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
神秘...
そして、私が GNU Javaインタプリタ でそれを実行するなら、それはほぼ100倍遅くなります、しかしa&&b || b&&c || a&&c
バージョンはそれから勝ちます。
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
Mac Java 1.6.0_26-b03-383-11A511を使ったPaul Waglandの結果
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
この種の質問は、 カルノーマップ で解決できます。
| C | !C
------|---|----
A B | 1 | 1
A !B | 1 | 0
!A !B | 0 | 0
!A B | 1 | 0
そこから、最初の行には1つのグループ、最初の列には2つのグループが必要であると推測され、ポリ潤滑剤の最適な解が得られます。
(C && (A || B)) || (A && B) <---- first row
^
|
first column without third case
読みやすさが目標です。コードを読む人はあなたの意図をすぐに理解しなければなりません。だからここに私の解決策があります。
int howManyBooleansAreTrue =
(a ? 1 : 0)
+ (b ? 1 : 0)
+ (c ? 1 : 0);
return howManyBooleansAreTrue >= 2;
return (a==b) ? a : c;
説明:
a==b
の場合、両方が真、または両方が偽です。両方とも真であれば、2つの真のブール値が見つかり、(a
を返すことで)trueを返すことができます。両方ともfalseの場合、c
がtrueであっても2つのtrueブール値はあり得ないため、(a
を返すことによって)falseを返します。それが(a==b) ? a
の部分です。 : c
はどうですか? a==b
がfalseの場合、a
またはb
のどちらか一方が真でなければなりません。そのため、最初の真のブール値を見つけたので、c
も真である場合に限り、c
を返します。
あなたは演算子の短絡形を使う必要はありません。
return (a & b) | (b & c) | (c & a);
これはあなたのバージョンと同じ数の論理演算を実行しますが、完全にブランチレスです。
これがテスト駆動の一般的なアプローチです。これまでに提供されてきたソリューションのほとんどほど「効率的」ではありませんが、明確で、テストされ、機能し、そして一般化されています。
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;
}
}
それを合計しなさい。これは、ブール代数と呼ばれています。
0 x 0 = 0
1 x 0 = 0
1 x 1 = 1
0 + 0 = 0
1 + 0 = 1
1 + 1 = 0 (+ carry)
そこに真理値表を見れば、乗算はブール値であり、単純に加算はxorであることがわかります。
あなたの質問に答えるには:
return (a + b + c) >= 2
それは本当にあなたが「改善した」という意味によって異なります。
もっと明確?
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.
どれが「改善された」かは状況によって大きく異なります。
boolean atLeastTwo(boolean a, boolean b, boolean c)
{
return ((a && b) || (b && c) || (a && c));
}
これはmap/reduceを使った別の実装です。これは、何十億ものブール値に対応します。© 分散環境では。 MongoDBを使う:
ブール値のデータベースvalues
を作成する:
db.values.insert({value: true});
db.values.insert({value: false});
db.values.insert({value: true});
マップを作成して関数を減らします。
編集:好きです CurtainDog's答え 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;
}
ランニングマップ/リデュース:
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;
}
直接コードの別の例:
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 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による最新の回答を参照してください。
最も明白な改良点は次のとおりです。
// 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));
}
しかし、それらの改善は軽微です。
これを行うには別の方法がありますが、それほど良い方法ではありません。
return (Boolean.valueOf(a).hashCode() + Boolean.valueOf(b).hashCode() + Boolean.valueOf(c).hashCode()) < 3705);
Boolean
ハッシュコード値は、trueの場合は1231、falseの場合は1237に固定されているため、<= 3699
を使用することもできます。
私は三項(一番上の答えからreturn a ? (b || c) : (b && c);
)が好きではありません、そして私は誰かがそれを言及するのを見たとは思いません。これは次のように書かれています。
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if (a) {
return b||c;
}
else {
return b&&C;
}
Clojure に:
(defn at-least [n & bools]
(>= (count (filter true? bools)) n)
使用法:
(at-least 2 true false true)
私はまだ私がこの解決策を見たとは思わない:
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;
}
その利点は、それがあなたが探している数に達すると、それが壊れることです。そのため、最初の2つが実際に当てはまる場合、これが「この1,000,000個の値のうち少なくとも2個が当てはまる」という場合、それはより一般的ないくつかの解決策よりも速くなります。
コードをどのように改善すべきかは明記されていないので、コードをより面白くすることによってコードを改善するように努力します。これが私の解決策です:
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);
しかし今ではもう面白くないです。
ブールを整数に変換して、この簡単なチェックを実行できます。
(int(a) + int(b) + int(c)) >= 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;
}
Function ReturnTrueIfTwoIsTrue(bool val1, val2, val3))
{
return (System.Convert.ToInt16(val1) +
System.Convert.ToInt16(val2) +
System.Convert.ToInt16(val3)) > 1;
}
やり方が多すぎます...
@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の答えよりほんの少し速いので、(私のHP/Intelラップトップでは)pdoxは全体的に最速です。
文字通りの解釈は、すべての主要言語で機能します。
return (a ? 1:0) + (b ? 1:0) + (c ? 1:0) >= 2;
しかし、私はおそらく、人々が読みやすく、3人以上に拡張できるようにしたいと思います。これは、多くのプログラマーによって忘れられているようです。
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;
}
return 1 << $a << $b << $c >= 1 << 2;
混乱せず、また読みやすくもない最も簡単な方法(IMO):
// Three booleans, check if two or more are true
return ( a && ( b || c ) ) || ( b && c );
そのはず:
(a || b && c) && (b || c && a)
また、true
が自動的に1
に、false
を0
に変換すると、
(a + b*c) * (b + c*a) > 0
Rubyでは:
[a, b, c].count { |x| x } >= 2
これはJRVMyのJavaVM上で実行できます。 ;-)
私が質問を見たときに私が最初に思ったのは、
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番目の変数を追加した場合はどうなりますか?実行時に変数の数が決定され、未知のサイズのブール値の配列が渡された場合はどうなりますか?数え上げに依存する解決策は、可能性のあるすべての組み合わせのリストに依存する解決策よりもはるかに簡単に拡張できます。また、すべての可能な組み合わせをリストするとき、私は間違いを犯すのがはるかに簡単であると思います。 「any 3 of 4」のコードを書いてみたり、見逃したり複製したりしないようにしてください。それでは "any 5 of 7"で試してみてください。
彼はおそらく、ビット単位の比較演算子のような複雑なもの(通常は複雑ではありませんが、ビット演算子を使用するのは非常に奇妙です)や、intに変換して合計するような非常に迂回するものを探していません。
これを解決する最も直接的で自然な方法は、次のような表現です。
a ? (b || c): (b && c)
お望みであれば関数に入れてください。しかしそれほど複雑ではありません。解決策は論理的に簡潔で効率的です。
この種のものはよく読んでいます:
if (a) {
return b || c;
}
else {
return b && c;
}
Cでは:
return !!a + !!b + !!c >= 2;
真理値表で計算します。
return (a & b) | (c & (a ^ b));
実際のコーディング能力よりも、問題の解決方法や考え方についての質問です。
もう少し簡潔なバージョンは
return((a ^ b)&&(b ^ c))^ b
しかし、前のポスターが言ったように、私が作業していたコードでこれを見た場合、誰かが耳にします。 :)
X = OR(a + b、c)
a b c X
1 1 0 1
0 0 1 1
0 1 1 1
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;
}
Java 8の通貨、私は本当にこのようなものを好む:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
return Stream.of(a, b, c).filter(active -> active).count() >= 2;
}
私はこの解決策を見つけました。
boolean atLeastTwo(boolean a, boolean b, boolean c) {
bool result = !(a ^ b ^ c) && !(!a & !b & !c) || (a & b & c);
return result;
}
この質問に対する最善の答えは、「従業員として、パフォーマンスに必要な場合に効率を維持しながら、自分の意味を明確にするために私がそれを書くことが重要です」ということです。これを書く方法は次のとおりです。
function atLeastTwoAreTrue(a, b, c) {
return (a && b) || (b && c) || (a && c);
}
実際には、テストは非常に工夫されているので、あなたが単純なコメントでそれを受け入れるならば、最速で最も不可解な方法を書くことは完全に受け入れられます。しかし、一般に、このワンライナーの世界では、この世界でもっと読みやすいコードが必要です。 :-)
3つのブール値をA、B、Cとします。
K-MAPを使って、ブール式を使うことができます。
この場合、ブール式はA(B + C)+ Cになります。
またはif((A &&(B || C))|| C){trueを返す。それ以外の場合はfalseを返します。
提起された問題の2と3は明らかに魔法のような数字です。 「正しい」答えは、インタビュアーがあなたのブール論理を理解しようとしていたか(そしてこの点でpdoxの答えが破綻する可能性があるとは思わない)、あるいはあなたが建築問題について理解しているかどうかによって異なります。
私は、任意の条件を持つあらゆる種類のリストを受け付けるmap-reduceソリューションを採用したいと思います。
ちなみに、これは全加算器の単なるキャリーアウトビットです。ハードウェアでは、論理演算を使用して、さまざまなブール式に基づいて最適な回路を決定できます。私は、伝統的なXOR解決策は、ポスターが提示した簡潔ではない表現よりも多くの努力を要すると思います。
私が他の人が指摘したことを見たことがないということの一つは、就職の面接の「私にいくつかのコードを書いてください」のセクションでやるべき標準的なことはまたは「それに完全に満足していますか」または「できるだけ最適化されていますか?」あなたが言うとあなたは終わった。 「これはどのように改善されるのでしょうか」と「あなたはそれをどのように改善するのか」と聞いた可能性があります。この場合、if(x) return true; else return false;
イディオムを単なるreturn x
に変更することは改善です - しかし、彼らがあなたが質問にどう反応するかを見たいだけの時があることに注意してください。インタビュアーの中には、完璧なコードに欠陥があると主張する人もいるだろうと聞いています。
(a||b) && (a||c)
- Javaでは、OPの6つではなく3つの比較を使用します。
間違って、私は以前にチェックしたはずです。
目的が3つのオペランドに対してビットごとの2/3の値を返すことである場合、算術および反復アプローチは比較的効果的ではない傾向があります。多くのCPUアーキテクチャでは、良い形式は「return((a | b)&c)|(a&b);」です。それは4つのブール演算を取ります。シングルアキュムレータマシン(小型の組み込みシステムで一般的)では、1バイトあたり合計7命令を使用する傾向があります。 "return(a&b)|(a&c)|(b&c);"という形式見栄えはいいかもしれませんが、1つのアキュムレータマシンでは、5つのブール演算、または1バイトあたり9つの命令が必要です。
ちなみに、CMOSロジックでは、「3つのうち2つではない」を計算するには12個のトランジスタが必要です(比較のため、インバータには2個、2入力NANDまたはNORには4個、そして3入力NANDまたはNORには6が必要です。
三項演算子はオタクジュースを流しますが、混乱を招く可能性があります(コードの保守性が低下するため、バグインジェクションの可能性が高まります)。 Jeff Attwood はここでそれをよく言った:
これは、まったく意味のない1回の書き込み時の節約と、数十回の読み取り時の解釈のペナルティとのトレードオフの完璧な例です。
三項演算子を避けて、私は以下の関数を作成しました:
function atLeastTwoTrue($a, $b, $c) {
$count = 0;
if ($a) { $count++; }
if ($b) { $count++; }
if ($c) { $count++; }
if ($count >= 2) {
return true;
} else {
return false;
}
}
他の解決策と同じくらいクールですか。わかりやすいですか。はい。それは保守性が良く、バグの少ないコードになるでしょうか。はい。
パフォーマンスのコンテキストではなく、優れたコード(再利用可能な拡張可能で読み取り可能なコード)
static boolean trueBooleans (int howMany,boolean ... bools)
{
int total = 0;
for (boolean b:bools)
if (b && (++total == howMany)) return true;
return false;
}
Javaを書くときの私の控え目な意見では、予期しない変更を簡単に処理してコードを複製しないことが、簡潔な(スクリプト言語のドメイン)または高速なプログラムよりも重要です。
C# では、頭の上からは、
public bool lol(int minTrue, params bool[] bools)
{
return bools.Count( ( b ) => b ) >= minTrue;
}
かなり速いはずです。
呼び出しは次のようになります。
lol( 2, true, true, false );
この方法では、ルールをメソッドに埋め込むのではなく、呼び出し側にルールを任せます(2つは当てはまります)。
この問題に対する非限定的な解決策は次のとおりです。
a'bc + abc' + abc + ab'c
K-Mapsを使うと、次のようになります。
bc + ab + ac
A'bcおよびabc '最小項に排他的論理和を使用し、abcおよびab'c最小項を組み合わせることで、これをさらに減らすことができます。
b(a ^ c) + ac
これはどう:
(a - b) ? c : a
Java 8の Stream 機能を使用して、これに別のアプローチを取ります。任意の数の任意のブール値に対して。すべての要素を処理する前にStreamが制限に達すると、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
子:
if (!!a + !!b + !!c >= 2)
public static boolean atLeast(int atLeastToBeTrue, boolean...bools){
int booleansTrue = 0;
for(boolean tmp : bools){
booleansTrue += tmp ? 1 : 0;
}
return booleansTrue >= atLeastToBeTrue;
}
varargs
a.k.a at least
:-)から、何個のboolean[]
を真にしたいかを選ぶことができます。
関数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); ]]
もしブール値を数に変換し、その数が2のべき乗でなければ、少なくとも2つの真理があります。
a*4 + b*2 + c*1 = N
return( N != 0 && (N&(N-1)) != 0)
私はただ選択肢を与えています。
私には、3つのうち3つはまったく任意の数であり、関数は任意の数で機能するはずです。それで、質問に答えるために、私は配列のxが真ならばうまくいくであろう関数を書きたいでしょう、例えば、
bool istrue ( int x, bool[] list)
y = count true in list
return y >= x
関数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;
}
問題を解決するために三項演算子を使用する最も簡単な形式は、次のとおりです。
return a ? (b ? true : c) : (b ? c : false);
また、要件の二重否定を使用して解決策を見つけることに投資することもできます。つまり、少なくとも2つの真の値の代わりに、最大1つの偽の値を満たす必要があります。
もう一つ:
return a? b||c : b&&c