Un intervieweur m'a récemment posé cette question: étant donné trois variables booléennes, a, b et c, la valeur est vraie si au moins deux des trois sont vraies.
Ma solution suit:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if ((a && b) || (b && c) || (a && c)) {
return true;
}
else{
return false;
}
}
Il a dit que cela pourrait encore être amélioré, mais comment?
Plutôt que d'écrire:
if (someExpression) {
return true;
} else {
return false;
}
Écrire:
return someExpression;
En ce qui concerne l'expression elle-même, quelque chose comme ceci:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
return a ? (b || c) : (b && c);
}
ou ceci (selon ce que vous trouvez plus facile à saisir):
boolean atLeastTwo(boolean a, boolean b, boolean c) {
return a && (b || c) || (b && c);
}
Il teste a
et b
exactement une fois et c
au plus une fois.
Juste pour utiliser XOR pour répondre à un problème relativement simple ...
return a ^ b ? c : a
Pourquoi ne pas l'appliquer littéralement? :)
(a?1:0)+(b?1:0)+(c?1:0) >= 2
En C, vous pouvez simplement écrire a+b+c >= 2
(ou !!a+!!b+!!c >= 2
pour être très sûr).
En réponse à la comparaison du bytecode Java par TofuBeer, voici un test de performance simple:
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);
}
}
}
Ceci imprime ce qui suit sur ma machine (exécutant Ubuntu sur Intel Core 2 + Sun Java 1.6.0_15-b03 avec HotSpot Server VM (14.1-b02, mode mixte)):
Première et deuxième itérations:
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
Itérations ultérieures:
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
Je me demande ce que Java VM pourrait faire que dégrade} performances dans le temps pour (a + b + c> = 2).
Et voici ce qui se passe si je lance Java avec un commutateur -client
VM:
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
Mystère...
Et si je le lance dans GNU interpréteur Java , il est presque 100 fois plus lent, mais la version a&&b || b&&c || a&&c
gagne à ce moment-là.
Résultats de Tofubeer avec le dernier code sous 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
Résultats de Paul Wagland avec un 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
Ce genre de questions peut être résolu avec Karnaugh Map :
| C | !C
------|---|----
A B | 1 | 1
A !B | 1 | 0
!A !B | 0 | 0
!A B | 1 | 0
à partir duquel vous indiquez que vous avez besoin d'un groupe pour la première ligne et de deux groupes pour la première colonne, pour obtenir la solution optimale de polygélubrifiants:
(C && (A || B)) || (A && B) <---- first row
^
|
first column without third case
La lisibilité devrait être l'objectif. Quelqu'un qui lit le code doit comprendre votre intention immédiatement. Alors voici ma solution.
int howManyBooleansAreTrue =
(a ? 1 : 0)
+ (b ? 1 : 0)
+ (c ? 1 : 0);
return howManyBooleansAreTrue >= 2;
return (a==b) ? a : c;
Explication:
Si a==b
, alors les deux sont vrais ou les deux sont faux. Si les deux sont vrais, nous avons trouvé nos deux vrais booléens et pouvons le rendre vrai (en retournant a
). Si les deux sont faux, il ne peut pas y avoir deux vrais booléens, même si c
est vrai, nous retournons donc false (en retournant a
). C'est la partie (a==b) ? a
. Qu'en est-il de : c
? Eh bien, si a==b
est faux, alors exactement l'un des a
ou b
doit être vrai, nous avons donc trouvé le premier booléen vrai, et la seule chose qui compte est que si c
soit également vrai, nous retournons donc c
.
Vous n'avez pas besoin d'utiliser les formes de court-circuit des opérateurs.
return (a & b) | (b & c) | (c & a);
Ceci effectue le même nombre d'opérations logiques que votre version, mais est complètement sans branche.
Voici une approche générale axée sur les tests. Pas aussi "efficace" que la plupart des solutions proposées jusqu'à présent, mais clair, testé, fonctionnel et généralisé.
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;
}
}
Résumer. Cela s'appelle l'algèbre booléenne pour une raison:
0 x 0 = 0
1 x 0 = 0
1 x 1 = 1
0 + 0 = 0
1 + 0 = 1
1 + 1 = 0 (+ carry)
Si vous regardez les tables de vérité ici, vous pouvez voir que la multiplication est booléenne et que, simplement, l'addition est xor.
Pour répondre à ta question:
return (a + b + c) >= 2
Cela dépend vraiment de ce que vous entendez par "amélioré":
Plus clair?
boolean twoOrMoreAreTrue(boolean a, boolean b, boolean c)
{
return (a && b) || (a && c) || (b && c);
}
Terser?
boolean moreThanTwo(boolean a, boolean b, boolean c)
{
return a == b ? a : c;
}
Plus général?
boolean moreThanXTrue(int x, boolean[] bs)
{
int count = 0;
for(boolean b : bs)
{
count += b ? 1 : 0;
if(count > x) return true;
}
return false;
}
Plus évolutif?
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;
}
Plus rapide?
// Only profiling can answer this.
Lequel est "amélioré" dépend fortement de la situation.
boolean atLeastTwo(boolean a, boolean b, boolean c)
{
return ((a && b) || (b && c) || (a && c));
}
Voici une autre implémentation utilisant map/reduction. Cela va bien à milliards de booléens© dans un environnement distribué. Utiliser MongoDB:
Création d'une base de données values
of booleans:
db.values.insert({value: true});
db.values.insert({value: false});
db.values.insert({value: true});
Créer la carte, réduire les fonctions:
Edit: J'aime CurtainDog'sanswer à propos du fait que map/reduction s'applique aux listes génériques. Voici donc une fonction de la carte qui prend un rappel qui détermine si une valeur doit être comptée ou non.
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;
}
Exécution de la carte/réduction:
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;
}
Un autre exemple de code direct:
int n = 0;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 2);
Ce n'est pas le code le plus succinct, évidemment.
Addenda
Une autre version (légèrement optimisée) de ceci:
int n = -2;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 0);
Cela peut être un peu plus rapide, en supposant que la comparaison avec 0 utilise un code plus rapide (voire moins) que la comparaison avec 2.
Prenant les réponses (jusqu'à présent) ici:
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);
}
}
et les exécuter dans le décompilateur (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
}
Vous pouvez voir que les?: Sont légèrement meilleures que la version corrigée de votre original. Celui qui est le meilleur est celui qui évite complètement de créer des ramifications. C’est bien du point de vue de moins d’instructions (dans la plupart des cas) et mieux pour les parties de la prédiction de branche du processeur, puisqu’une hypothèse erronée dans la prédiction de branche peut provoquer un blocage du processeur.
Je dirais que le plus efficace est celui de Moonshadow. Il utilise le moins d'instructions en moyenne et réduit les risques de blocage du pipeline dans la CPU.
Pour être sûr à 100%, vous devez connaître le coût (en cycles de la CPU) pour chaque instruction, qui, malheureusement, n'est pas facilement disponible (vous devez regarder la source du hotspot, puis les spécifications du fournisseur de la CPU pour le temps imparti). prises pour chaque instruction générée).
Voir la réponse mise à jour par Rotsor pour une analyse d'exécution du code.
Les améliorations les plus évidentes sont les suivantes:
// 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;
}
et alors
// 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));
}
Mais ces améliorations sont mineures.
Encore une autre façon de faire mais pas une très bonne:
return (Boolean.valueOf(a).hashCode() + Boolean.valueOf(b).hashCode() + Boolean.valueOf(c).hashCode()) < 3705);
Les valeurs de hashcode Boolean
sont fixées à 1231 pour true et à 1237 pour false, de sorte que vous auriez également utilisé <= 3699
Je n'aime pas ternary (return a ? (b || c) : (b && c);
de la réponse du haut), et je ne pense pas avoir vu quelqu'un en parler. C'est écrit comme ça:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if (a) {
return b||c;
}
else {
return b&&C;
}
Dans Clojure :
(defn at-least [n & bools]
(>= (count (filter true? bools)) n)
Usage:
(at-least 2 true false true)
Je ne pense pas avoir déjà vu cette solution:
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;
}
Son avantage est qu’une fois que le nombre que vous recherchez est atteint, il se brise. Donc, si cela était "au moins 2 des 1 000 000 valeurs sont vraies" alors que les deux premières sont vraies, alors cela devrait aller plus vite que certaines des solutions plus "normales".
Comme il n'a pas été précisé comment le code devrait être amélioré, je vais essayer de l'améliorer en le rendant plus amusant. Voici ma solution:
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;
}
Au cas où quelqu'un se demanderait si ce code fonctionne, voici une simplification utilisant la même logique:
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;
}
Cela peut se résumer comme suit:
return ((a || b) && (c)) || (a && b);
Mais maintenant, ce n'est plus drôle.
Nous pouvons convertir les bools en entiers et effectuer cette vérification facile:
(int(a) + int(b) + int(c)) >= 2
Une solution en C.
int two(int a, int b, int c) {
return !a + !b + !c < 2;
}
ou vous préférez peut-être:
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;
}
Trop de façons de le faire ...
En plus de l'excellent post de @TofuBeer TofuBeer, considérons la réponse de @pdox pdox:
static boolean five(final boolean a, final boolean b, final boolean c)
{
return a == b ? a : c;
}
Considérez aussi sa version désassemblée donnée par "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
la réponse de pdox est compilée avec moins de code d'octet que les réponses précédentes. Comment son temps d'exécution se compare-t-il aux autres?
one 5242 ms
two 6318 ms
three (moonshadow) 3806 ms
four 7192 ms
five (pdox) 3650 ms
Au moins sur mon ordinateur, la réponse de pdox est légèrement plus rapide que celle de @moonshadow moonshadow, ce qui en fait le plus rapide dans son ensemble (sur mon ordinateur portable HP/Intel).
Une interprétation littérale fonctionnera dans toutes les langues principales:
return (a ? 1:0) + (b ? 1:0) + (c ? 1:0) >= 2;
Mais je rendrais probablement les choses plus faciles à lire, et étendues à plus de trois - quelque chose qui semble être oublié de nombreux programmeurs
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;
Le moyen le plus simple (IMO) qui ne soit pas déroutant et facile à lire:
// Three booleans, check if two or more are true
return ( a && ( b || c ) ) || ( b && c );
CA devrait etre:
(a || b && c) && (b || c && a)
De plus, si true
est automatiquement converti en 1
et false
en 0
:
(a + b*c) * (b + c*a) > 0
En rubis:
[a, b, c].count { |x| x } >= 2
Qui pourrait être exécuté dans JRuby sur le JavaVM. ;-)
Ma première pensée quand j'ai vu la question était:
int count=0;
if (a)
++count;
if (b)
++count;
if (c)
++count;
return count>=2;
Après avoir vu d'autres messages, j'avoue que
return (a?1:0)+(b?1:0)+(c?1:0)>=2;
est beaucoup plus élégant. Je me demande quels sont les temps d'exécution relatifs.
Quoi qu’il en soit, je pense que ce type de solution est bien meilleur qu’une solution du
return a&b | b&c | a&c;
variété parce qu’elle est plus facilement extensible. Et si par la suite nous ajoutons une quatrième variable qui doit être testée? Que se passe-t-il si le nombre de variables est déterminé à l'exécution et qu'un tableau de booléens de taille inconnue nous est transmis? Une solution qui repose sur le comptage est beaucoup plus facile à étendre qu'une solution qui dépend de la liste de toutes les combinaisons possibles. En outre, lorsque je cite toutes les combinaisons possibles, je pense qu’il est beaucoup plus facile de se tromper. Par exemple, essayez d’écrire le code pour "n’importe quel 3 sur 4" et assurez-vous de ne rien rater ou de ne pas en dupliquer. Maintenant, essayez-le avec "any 5 of 7".
Il ne recherche probablement rien d'aussi compliqué que les opérateurs de comparaison de bits (pas normalement, mais avec des booléens, il est extrêmement étrange d'utiliser des opérateurs de bits) ou quelque chose de très compliqué comme convertir en int et les résumer.
La façon la plus directe et naturelle de résoudre ce problème est d'utiliser une expression comme celle-ci:
a ? (b || c): (b && c)
Mettez-le dans une fonction si vous préférez, mais ce n'est pas très compliqué. La solution est logiquement concise et efficace.
Ce genre de lecture se lit mieux:
if (a) {
return b || c;
}
else {
return b && c;
}
En C:
return !!a + !!b + !!c >= 2;
Calculé via une table de vérité:
return (a & b) | (c & (a ^ b));
Certainement une question qui concerne davantage la façon dont vous résolvez les problèmes/pensez que votre capacité de codage réelle.
Une version légèrement plus légère pourrait être
return ((a ^ b) && (b ^ c)) ^ b
Mais comme l'a dit une précédente affiche, si je voyais cela dans n'importe quel code sur lequel je travaillais, quelqu'un en aurait assez. :)
X = OU (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;
}
Actuellement avec Java 8, je préfère vraiment quelque chose comme ceci:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
return Stream.of(a, b, c).filter(active -> active).count() >= 2;
}
J'ai trouvé cette solution.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
bool result = !(a ^ b ^ c) && !(!a & !b & !c) || (a & b & c);
return result;
}
La meilleure réponse à la question devrait être "En tant qu'employé, il est important que je l'écrive afin que ma signification soit claire tout en maintenant l'efficacité lorsque cela est nécessaire à la performance." Voici comment je l'écrirais:
function atLeastTwoAreTrue(a, b, c) {
return (a && b) || (b && c) || (a && c);
}
En réalité, le test est tellement élaboré que la méthode la plus rapide et la plus cryptée possible est parfaitement acceptable si vous la modifiez avec un simple commentaire. Mais, en général, dans ce monde à une seule ligne, nous avons besoin d’un code plus lisible dans ce monde. :-)
Que les trois valeurs booléennes soient A, B et C ....
Vous pouvez utiliser un k-MAP et venir avec une expression booléenne ...
Dans ce cas, l'expression booléenne sera A (B + C) + C
ou si ((A && (B || C)) || C) { return true; } else return false;
Les 2 et 3 dans la question posée sont décidément magiques. La réponse "correcte" dépendra de savoir si l'intervieweur essayait de comprendre votre logique booléenne (et je ne pense pas que la réponse de pdox pourrait être améliorée à cet égard) ou votre compréhension des problèmes architecturaux.
Je serais enclin à opter pour une solution de réduction de la carte qui accepterait toute sorte de liste avec n'importe quelle condition arbitraire.
Pour votre information, ceci est juste le peu d'un reporteur complet. En matériel, vous pouvez utiliser l’effort logique pour déterminer le circuit optimal en fonction des différentes expressions booléennes. Je suppose que la solution traditionnelle XOR nécessiterait plus d’efforts que l’expression moins succincte présentée par l’affiche.
Une chose que je n’ai pas vue d’autre chose de dire, c’est que la chose la plus courante à faire dans la section "écrivez-moi un code" de l’entretien est de dire "Pourriez-vous améliorer cela?" ou "Êtes-vous complètement satisfait de cela" ou "est-ce aussi optimisé que possible?" quand vous dites que vous avez terminé. Il est possible que vous entendiez "comment amélioreriez-vous cela", alors que "cela pourrait être amélioré; comment?". Dans ce cas, changer l'idiome if(x) return true; else return false;
en return x
est une amélioration, mais sachez qu'il y a des moments où ils veulent juste voir comment vous réagissez à la question. J'ai entendu dire que certains enquêteurs insisteraient pour dire qu'il y a une faille dans le code parfait, juste pour voir comment vous allez la gérer.
Que diriez-vous de (a||b) && (a||c)
- Java, utilise trois comparaisons au lieu de six.
Faux, j'aurais dû vérifier plus tôt.
Si l'objectif est de retourner une valeur binaire deux sur trois pour trois opérandes, les approches arithmétiques et itératives risquent d'être relativement peu efficaces. Sur de nombreuses architectures de CPU, une bonne forme serait "return ((a | b) & c) | (a & b);". Cela prend quatre opérations booléennes. Sur les machines à un seul accumulateur (courantes dans les petits systèmes intégrés), il est généralement possible de prendre sept instructions par octet. Le formulaire "retour (a & b) | (a & c) | (b & c);" est peut-être plus esthétique, mais il faudrait cinq opérations booléennes, ou neuf instructions par octet sur une machine à un seul accumulateur.
Incidemment, dans la logique CMOS, le calcul "pas deux sur trois" nécessite douze transistors (à titre de comparaison, un onduleur en requiert deux, un NAND à deux entrées ou NOR en requiert quatre et ou NOR en nécessite six).
Les opérateurs ternaires obtiennent le jus de nerd qui coule, mais ils peuvent être déroutants (rendre le code moins maintenable, augmentant ainsi le potentiel d’injection de bogues). Jeff Attwood l'a bien dit ici :
C'est un exemple parfait de négociation une fois totalement dénuée de sens gain de temps d'écriture par rapport à des dizaines de pénalités de compréhension au moment de la lecture-- Il Me fait penser.
En évitant les opérateurs ternaires, j'ai créé la fonction suivante:
function atLeastTwoTrue($a, $b, $c) {
$count = 0;
if ($a) { $count++; }
if ($b) { $count++; }
if ($c) { $count++; }
if ($count >= 2) {
return true;
} else {
return false;
}
}
Est-ce aussi cool que certaines des autres solutions? Est-ce plus facile à comprendre? Oui. Cela conduira-t-il à un code plus facile à maintenir et moins bogué? Oui.
Pas dans le contexte de la performance, mais du bon code (code extensible et lisible pouvant être réutilisé)
static boolean trueBooleans (int howMany,boolean ... bools)
{
int total = 0;
for (boolean b:bools)
if (b && (++total == howMany)) return true;
return false;
}
À mon humble avis lors de l'écriture en Java, la gestion simple des modifications inattendues et l'absence de code dupliqué sont plus importantes que la concision (domaine des langages de script) ou un programme rapide.
Dans C # , comme si de rien n'était:
public bool lol(int minTrue, params bool[] bools)
{
return bools.Count( ( b ) => b ) >= minTrue;
}
devrait être assez rapide.
Un appel ressemblerait à ceci:
lol( 2, true, true, false );
De cette façon, vous laissez les règles (deux doivent être vraies) à l'appelant, au lieu de les incorporer à la méthode.
La solution non réduite à ce problème est la suivante:
a'bc + abc' + abc + ab'c
En utilisant K-Maps, on obtient:
bc + ab + ac
On pourrait réduire cela davantage en utilisant exclusive ou sur les minterms a'bc et abc 'et en combinant les minterms abc et ab'c
b(a ^ c) + ac
Celui-ci, ça va:
(a - b) ? c : a
Adoptez une autre approche en utilisant la fonctionnalité Stream de Java 8, pour un nombre quelconque de booléens avec un montant requis arbitraire. Le flux court-circuite s'il atteint la limite avant de traiter tous les éléments:
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));
}
Sortie:
1,2: true
1,1: true
1,0: false
1,1: true
2,3: true
3,2: false
3,3: true
C:
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;
}
Vous pouvez choisir combien de at least
vous voulez être vrai parmi varargs
a.k.a boolean[]
:-)
function atLeastTwoTrue ($ a, $ b, $ c) { int count = 0; compte = (a? compte + 1: compte); compte = (b? compte + 1: compte); count = (c? count + 1: count); return (count> = 2); }
Si je convertis les booléens en un nombre, et si le nombre n'est pas une puissance de deux, il a au moins deux vrais.
a*4 + b*2 + c*1 = N
return( N != 0 && (N&(N-1)) != 0)
Je ne fais que donner une alternative.
Il me semble que trois sur trois sont des nombres assez arbitraires, et la fonction devrait fonctionner avec un nombre arbitraire. Donc, afin de répondre à la question, j'écrirais une fonction qui fonctionnerait si x dans un tableau était vrai, par exemple,
bool istrue ( int x, bool[] list)
y = count true in list
return y >= x
La fonction ko
renvoie la réponse:
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;
}
La forme la plus simple utilisant des opérateurs ternaires pour résoudre le problème est la suivante:
return a ? (b ? true : c) : (b ? c : false);
Vous pouvez également vouloir investir dans la recherche d'une solution en utilisant la double négation de l'exigence, ce qui signifie qu'au lieu d'au moins deux valeurs vraies, vous devez satisfaire à la condition d'au plus une valeur fausse.
Un autre:
return a? b||c : b&&c