Résoudre le problème du secrétaire


13

Le problème du secrétaire est un problème célèbre décrit comme suit:

  1. Vous avez besoin d'une nouvelle secrétaire
  2. Vous avez N candidats que vous pouvez interroger un à la fois
  3. Vous pouvez noter chaque candidat après l'entretien. Votre système de notation ne donnera jamais à deux candidats le même score
  4. Après avoir interviewé un candidat, vous devez immédiatement dire «oui» ou «non»
  5. Vous souhaitez que le candidat avec le score le plus élevé

La solution consiste à interroger les premiers floor(N/e)candidats, puis à accepter le premier candidat qui a obtenu un score plus élevé que tous les candidats précédents. Si aucun des candidats n'est supérieur, renvoyez le dernier candidat. Chose intéressante, cela donne au candidat le plus haut 1/epourcentage du temps. efait référence au numéro d' Euler . Pour obtenir la valeur de e, vous pouvez utiliser un code intégré log, ou le coder en dur avec au moins 5 décimales.

Contribution:

Un tableau non vide d'entiers non négatifs uniques pas plus de 2^31-1.

Production:

Un entier représentant le candidat choisi. Pour être clair, l'algorithme est:

  1. Trouvez l'élément maximum dans les premiers floor(N/e)éléments du tableau.
  2. Parcourez les éléments restants et renvoyez le premier élément supérieur au maximum trouvé à l'étape 1.
  3. Si aucun des éléments n'est supérieur, retournez le dernier élément.

Par exemple, supposons que votre tableau était [2,7,4,3,9,20], ainsi N = 6et floor(N/e) = 2. Les 2 premiers éléments du tableau sont [2,7]. Le maximum de [2,7]est 7. Les éléments restants sont [4,3,9,20]. Le premier élément qui est supérieur à l' 7est 9, alors nous revenons 9.

Cas de test:

[0]         => 0
[100]       => 100
[100, 45]   => 100
[0, 1]      => 0
[45, 100]   => 45
[1, 4, 5]   => 4
[1, 5, 4]   => 5
[5, 4, 1]   => 1
[5, 1, 4]   => 4
[4, 1, 5]   => 5
[56, 7, 37, 73, 90, 59, 65, 61, 29, 16, 47, 77, 60, 8, 1, 76, 36, 68, 34, 17, 23, 26, 12, 82, 52, 88, 45, 89, 94, 81, 3, 24, 43, 55, 38, 33, 15, 92, 79, 87, 14, 75, 41, 98, 31, 58, 53, 72, 39, 30, 2, 0, 49, 99, 28, 50, 80, 91, 83, 27, 64, 71, 93, 95, 11, 21, 6, 66, 51, 85, 48, 62, 22, 74, 69, 63, 86, 57, 97, 32, 84, 4, 18, 46, 20, 42, 25, 35, 9, 10, 19, 40, 54, 67, 70, 5, 44, 13, 78, 96]
=> 98
[10, 68, 52, 48, 81, 39, 85, 54, 3, 21, 31, 59, 28, 64, 42, 90, 79, 12, 63, 41, 58, 57, 13, 43, 74, 76, 94, 51, 99, 67, 49, 14, 6, 96, 18, 17, 32, 73, 56, 7, 16, 60, 61, 26, 86, 72, 20, 62, 4, 83, 15, 55, 70, 29, 23, 35, 77, 98, 92, 22, 38, 5, 50, 82, 1, 84, 93, 97, 65, 37, 45, 71, 25, 11, 19, 75, 78, 44, 46, 2, 53, 36, 0, 47, 88, 24, 80, 66, 87, 40, 69, 27, 9, 8, 91, 89, 34, 33, 95, 30]
=> 30

Votre solution doit être O(n), où nest la longueur du tableau. Si votre langue a une fonction intégrée qui trouve le maximum d'un tableau, vous pouvez supposer que la fonction prendO(n) (et j'espère que c'est le cas).

Les échappatoires standard s'appliquent, et c'est un , alors faites la réponse la plus courte dans votre langue préférée!


1
Que efaut-il utiliser?
afuous


1
Ah, maintenant je comprends comment fonctionne l'algorithme. Je pensais que votre deuxième paragraphe signifiait que vous n'interrogez jamais les candidats après la parole (n / e).
Poignée de porte

1
J'ai demandé spécifiquement parce que dans certaines langues, il est plus court de définir une variable avec 5 décimales de précision que d'utiliser réellement la fonction intégrée e(par exemple Python, où e=2.71828est plus court que import math;math.E)
Mego

1
Remarque: «1 / e pour cent du temps» serait vraiment mauvais. C'est une probabilité de 1 / e, soit environ 37% du temps
edc65

Réponses:


4

Gelée, 13 octets

L:Øe³ḣȯ-Ṁ<i1ị

Certainement un algorithme O (n) , espérons-le une implémentation O (n) . Essayez-le en ligne!

Comment ça fonctionne

L:Øe³ḣȯ-Ṁ<i1ị  Main link. Argument: A (list of scores)

L              Get the length of A.
 :Øe           Divide the length by e, flooring the result.
    ³ḣ         Retrieve the that many scores from the beginning of A.
      ȯ-       Logical OR; replace an empty list with -1.
        Ṁ      Compute the maximum of those scores.
         <     Compare each score in A with that maximum.
          i1   Find the first index of 1 (0 if not found).
            ị  Retrieve the element of A at that index (the last one if 0).

3

CJam, 20 octets

q~___,1me/i<:e>f>1#=

Fonctionne de manière similaire à la suggestion de Dennis.

q~___                     Read array, duplicate three times
      ,                   Consume one to find the length
       1me/i              Push e then divide and take floor
            <             Take that many elements from the list
             :e>          Find maximum (Thanks to Dennis)
                f>        Label array elements larger than this as 1
                  1#      Find the first one (won't be in set of elements we've looked in)
                    =     Take that element from the final copy of the array. -1 gives us the last element as required

$W=ne fonctionne pas en temps linéaire.
Dennis

Urgh, tu as raison. Y a-t-il une meilleure façon de trouver le maximum dans CJam que vous connaissez?
Un Simmons

1
:e>(réduire au maximum)
Dennis

@Dennis Merci!
Un Simmons

2

Java, 128 118 octets

a->{int c=(int)(a.length/Math.E),i=0,m=-1,t=0;for(;i<a.length;i++){t=a[i];if(i<c)m=t>m?t:m;if(t>m)return t;}return t;}

Dentelé:

static Function<Integer[], Integer> secretary2 = a -> {
    int c = (int) (a.length/Math.E),     // c = floor(N/E)
        i = 0, m = -1, t = 0;            // declare vars early to save bytes
    for (;i<a.length;i++) {              // for each element of input
        t = a[i];                        // cache element to save bytes
        if (i<c)                         // if before c
            m = t>m ? t : m;             // m = max(m, element)
        if (t>m)                         // if element > m
            return t;                    // return: we've found our best
    }                                    // if never found a good element
    return t;                            // return the last element
};


2

JavaScript (ES6) 64

(a,l=a.length/Math.E,x)=>(a.every(v=>--l>0?x>v?1:x=v:(z=v)<x),z)

Moins golfé

(
 a, 
 l=a.length/Math.E, // limit for stage 1
 x // init at undefined
)=>(
  a.every(v => --l > 0 // checking for >0 no need to floor
          ? x>v?1:x=v // stage 1, find max in x, always return truthy
          : (z=v)<x ) // stage 2, set z to current value and exit early if z>x
  , z // at last z has the last seen value
)

Tester

f=(a,l=a.length/Math.E,x)=>(a.every(v=>--l>0?x>v?1:x=v:(z=v)<x),z)

console.log=x=>O.textContent+=x+'\n'

;[ 
 [0], [100], [0,1], [1,2,3],
 [100, 45],
 [45, 100],
 [1, 4, 5],
 [1, 5, 4],
 [5, 4, 1],
 [5, 1, 4],
 [4, 1, 5],   
 [10, 68, 52, 48, 81, 39, 85, 54, 3, 21, 31, 59, 28, 64, 42, 90, 79, 12, 63, 41, 58, 57, 13, 43, 74, 76, 94, 51, 99, 67, 49, 14, 6, 96, 18, 17, 32, 73, 56, 7, 16, 60, 61, 26, 86, 72, 20, 62, 4, 83, 15, 55, 70, 29, 23, 35, 77, 98, 92, 22, 38, 5, 50, 82, 1, 84, 93, 97, 65, 37, 45, 71, 25, 11, 19, 75, 78, 44, 46, 2, 53, 36, 0, 47, 88, 24, 80, 66, 87, 40, 69, 27, 9, 8, 91, 89, 34, 33, 95, 30],
[56, 7, 37, 73, 90, 59, 65, 61, 29, 16, 47, 77, 60, 8, 1, 76, 36, 68, 34, 17, 23, 26, 12, 82, 52, 88, 45, 89, 94, 81, 3, 24, 43, 55, 38, 33, 15, 92, 79, 87, 14, 75, 41, 98, 31, 58, 53, 72, 39, 30, 2, 0, 49, 99, 28, 50, 80, 91, 83, 27, 64, 71, 93, 95, 11, 21, 6, 66, 51, 85, 48, 62, 22, 74, 69, 63, 86, 57, 97, 32, 84, 4, 18, 46, 20, 42, 25, 35, 9, 10, 19, 40, 54, 67, 70, 5, 44, 13, 78, 96]
].forEach(t=>{
  var r=f(t)
  console.log(r+' : '+t)
})
<pre id=O></pre>


1

Ruby, 64 octets

->a{m=a[0...c=a.size/Math::E].max
a[c..-1].find{|n|n>m}||a[-1]}

2
@Doorknob Il parcourt une fois les éléments du premier étage (N / e) pour trouver le maximum, puis parcourt le reste de la liste dans le pire des cas en comparant chaque élément au maximum. Il n'y a qu'une seule comparaison par élément dans les deux parties.
afuous

Ah, c'est vrai. J'ai mal lu et j'ai pensé que vous trouviez le maximum à chaque itération.
Poignée de porte

1
En fait, je pense que c'est toujours O (n) si vous venez de le faire a.finddans la deuxième étape, même si évidemment c'est beaucoup moins efficace.
histocrate

1
Vous pouvez utiliser (0...c)pour une plage qui exclut c.
histocrate

@histocrate Oui, ce devrait être O (2n) qui est O (n)
Pas que Charles

1

PARI / GP , 70 octets

Cela peut avoir des problèmes sur les anciennes versions de gp quand on lui donne un singleton, mais cela fonctionne au moins à partir de la révision 18487.

v->m=vecmax(v[1..t=#v\exp(1)]);for(i=t+1,#v,v[i]>m&&return(v[i]));v[#v]

1

JavaScript (ES6), 79 octets

a=>(m=Math.max(...a.splice(0,a.length/Math.E)),a.slice(a.findIndex(x=>x>m))[0])

Fonctionne car findIndexretourne -1en cas d'échec, mais a.slice(-1)[0]renvoie le dernier élément du tableau comme souhaité.


1

Python 2, 87 octets

a=input()
t=int(len(a)/2.71828)
m=max(a[:t]+[-1])
for x in a[t:]:
 if x>m:break
print x

L'utilisateur entre le tableau sous forme de liste, avec crochets et virgules. Python 2input() commande de est pratique ici.

Que nous mettions fin au processus tôt ou non, nous embauchons la dernière personne interrogée.



1

Python 3.5; 110 octets:

def Interview(h):k=max(h[0:int(len(h)/2.71828)-1]);n=max(h[int(len(h)/2.71828)-1:len(h)-1]);return max([k, n])

Fondamentalement, ce qui précède fait qu'il prend d'abord un tableau fourni, "h" tant qu'il comprend plus de 5 éléments (pour l'instant ...), trouve la valeur maximale dans le premier (longueur du tableau (len (h )) / Nombre d'Euler (à 5 décimales)) des éléments de ce tableau, puis renvoie cette valeur sous la forme "k". De plus, "n" est la valeur maximale dans le reste du tableau. Enfin, la valeur renvoyée par la fonction est la valeur maximale dans un tableau contenant à la fois "k" et "n".

Remarque: La max()fonction de Python est la complexité O (n).

Ci-dessous, un golf sans code plus lisible la version du code ci - dessus qui a un aléatoire, unique tableau 10 élément fourni, confirmer que cela fonctionne:

import random, math

def Interview():
    k = max(h[0:int(len(h)/math.e)-1])
    n = max(h[int(len(h)/math.e)-1:len(h)-1])
    return max([k, n])

h = random.sample(range((2*31)-1), 10)

print(Interview(h))

Bienvenue chez PPCG! Vous pouvez séparer vos importations par des virgules. De plus, vous n'avez pas besoin de générer le tableau vous-même, vous pouvez donc supprimer cette partie du code (simplement avoir le tableau comme paramètre de la fonction)
Nathan Merrill

@NathanMerrill Oui, je pensais à faire ça, mais j'ai pensé que vous n'aimeriez pas vraiment ça, mais maintenant que je sais que cela n'a pas vraiment d'importance, je vais modifier ma réponse. Merci aussi pour le conseil sur la virgule séparant mes importations. J'avais totalement oublié ça!
R. Kap

Autres conseils: vous avez beaucoup d'espaces blancs inutiles (après des virgules, entre des signes égaux. Vous n'avez pas besoin non plus d'une instruction d'impression à la fin.
Nathan Merrill

@NathanMerrill Merci pour les conseils! Je garderai cela à l'esprit en faisant plus de golf de code! :)
R. Kap
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.