web-dev-qa-db-fra.com

Vérifiez si au moins deux booléens sur trois sont vrais

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?

566
user282886

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.

Références

809
polygenelubricants

Juste pour utiliser XOR pour répondre à un problème relativement simple ...

return a ^ b ? c : a
483
Tim Stone

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
212
Rotsor

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
142
Jack

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;
139
danatel
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.

133
pdox

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.

34
moonshadow

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;
    }
}
27
Carl Manaster

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
24
memet

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.

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

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

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.

13
David R Tribble

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.

13
TofuBeer

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.

12
TofuBeer

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

12
barrowc

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;
    }
10
Roman A. Taycher

Dans Clojure :

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

Usage:

(at-least 2 true false true)
8
Vagif Verdi

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".

6
Joe Enos

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.

6
Bruce Attah

Nous pouvons convertir les bools en entiers et effectuer cette vérification facile:

(int(a) + int(b) + int(c)) >= 2
6
vine'th

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;
}
5
Suvega
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 ...

5
Duby

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

4
Barzee

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;
}
4
blakecallens
return 1 << $a << $b << $c >= 1 << 2;
4
Kevin

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

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
3
Dimitre Novatchev

En rubis:

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

Qui pourrait être exécuté dans JRuby sur le JavaVM. ;-)

3
user373826

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".

3
Jay

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.

3
stinky472

Ce genre de lecture se lit mieux:

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

En C:

return !!a + !!b + !!c >= 2;
3
Matt Joiner

Calculé via une table de vérité:

return (a & b) | (c & (a ^ b));
3
z-index

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

2
Kintar

X = OU (a + b, c)

a b c X

1 1 0 1

0 0 1 1

0 1 1 1

2
dai
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;
}
2
endy

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

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

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

2
ZaBlanc

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;

2
Egalitarian

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.

2
CurtainDog

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.

2
Ben Manes

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.

2
Kate Gregory

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.

2
d1val

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

2
supercat

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.

2
labratmatt

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.

2
teodozjan

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.

2
Aaron

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
2
SirensOfTitan

Celui-ci, ça va:

(a - b) ? c : a
1
binary_baba

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
1
mkobit

C:

if (!!a + !!b + !!c >= 2)
1
Matt Joiner
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[] :-)

0
To Kra
 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); 
} 
0
itpatil

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.

0
Kshitij Banerjee

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
0
Derek Organ

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

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.

0
Melvin Protacio

Un autre:

return a? b||c : b&&c
0
nabil london