Risolvi il problema del segretario


13

Il problema del segretario è un famoso problema descritto così:

  1. Hai bisogno di un nuovo segretario
  2. Hai N candidati che puoi intervistare uno alla volta
  3. Sei in grado di segnare ciascun candidato dopo il colloquio. Il tuo sistema di punteggio non assegnerà mai a due candidati lo stesso punteggio
  4. Dopo aver intervistato un candidato, è necessario fornire immediatamente un "sì" o "no"
  5. Vuoi il candidato con il punteggio più alto

La soluzione è di intervistare i primi floor(N/e)candidati e quindi accettare il primo richiedente che ha un punteggio più alto rispetto a tutti i precedenti candidati. Se nessuno dei candidati è superiore, restituisce l'ultimo richiedente. Abbastanza interessante, questo dà il miglior candidato 1/epercentuale del tempo. esi riferisce al numero di Eulero . Per ottenere il valore di e, è possibile utilizzare un built-in logo codificarlo con almeno 5 punti decimali.

Ingresso:

Un array non vuoto di interi univoci non negativi non più di 2^31-1.

Produzione:

Un numero intero che rappresenta il candidato scelto. Per essere chiari l'algoritmo è:

  1. Trova l'elemento massimo nei primi floor(N/e)elementi dell'array.
  2. Scorrere gli elementi rimanenti e restituire il primo elemento che è superiore al massimo trovato nel passaggio 1.
  3. Se nessuno degli elementi è superiore, restituisce l'ultimo elemento.

Ad esempio, supponiamo che il tuo array fosse [2,7,4,3,9,20], quindi N = 6e floor(N/e) = 2. I primi 2 elementi dell'array sono [2,7]. Il massimo di [2,7]è 7. Gli elementi rimanenti sono [4,3,9,20]. Il primo elemento che è maggiore di 7è 9, quindi torniamo9 .

Casi 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

La soluzione deve essere O(n), dov'è nla lunghezza dell'array. Se la tua lingua ha un builtin che trova il massimo di un array, puoi presumere che la funzione abbiaO(n) (e si spera lo sia).

Si applicano scappatoie standard, e questo è un , quindi fai la risposta più breve nella tua lingua preferita!


1
Cosa edovrebbe essere usato?
afuoso


1
Ah, ora capisco come funziona l'algoritmo. Pensavo che il tuo secondo paragrafo significasse che non hai mai intervistato i candidati dopo il primo piano (n / e).
Maniglia della porta

1
Ho chiesto specificamente perché in alcune lingue è più breve definire una variabile con 5 punti decimali di precisione piuttosto che usare effettivamente il builtin e(ad esempio Python, dove e=2.71828è più corto di import math;math.E)
Mego

1
Nota: "1 / e percento delle volte" sarebbe davvero brutto. È una probabilità di 1 / e, circa il 37% delle volte
edc65

Risposte:


4

Gelatina, 13 byte

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

Sicuramente un algoritmo O (n) , si spera un'implementazione O (n) .Provalo online!

Come funziona

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 byte

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

Funziona in modo simile al suggerimento di 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=non funziona in tempo lineare.
Dennis,

Urgh, hai ragione. Esiste un modo migliore per trovare il massimo in CJam che conosci?
A Simmons,

1
:e>(ridurre al massimo)
Dennis

@Dennis Grazie!
A Simmons,

2

Java, 128 118 byte

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

rientrato:

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)

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

Test

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

Rubino, 64 byte

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

2
@Doorknob Passa attraverso gli elementi del primo piano (N / e) una volta per trovare il massimo, quindi passa attraverso il resto dell'elenco nel peggiore dei casi confrontando ogni elemento con il massimo. Esiste un solo confronto per elemento in entrambe le parti.
afuoso

Ah, esatto. Ho letto male e ho pensato che stavi trovando il massimo in ogni iterazione.
Maniglia della porta

1
In effetti, penso che sia ancora O (n) se lo fai a.find nel secondo passaggio, anche se ovviamente è molto meno efficiente.
istocratico

1
È possibile utilizzare (0...c)per un intervallo che esclude c.
istocratico

@histocrat Sì, dovrebbe essere O (2n) che è O (n)
Non che Charles

1

PARI / GP , 70 byte

Questo può avere problemi con le versioni precedenti di gp quando viene dato un singleton, ma funziona almeno dalla revisione 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 byte

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

Funziona perché findIndexrestituisce -1errori, ma a.slice(-1)[0]restituisce l'ultimo elemento dell'array come desiderato.


1

Python 2, 87 byte

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'utente inserisce l'array come un elenco, con parentesi quadre e virgole. Python 2'sinput() comando di è comodo qui.

Indipendentemente dalla conclusione anticipata del processo, assumiamo l'ultima persona che è stata intervistata.



1

Python 3.5; 110 byte:

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

Fondamentalmente, ciò che fa sopra è che in primo luogo prende un array fornito, "h" fintanto che include più di 5 elementi (per ora ...), trova il valore massimo nel primo (lunghezza dell'array (len (h )) / Numero di Eulero (con 5 cifre decimali)) voci di quell'array, quindi restituisce quel valore come "k". Inoltre, "n" è il valore massimo nel resto dell'array. Infine, il valore restituito dalla funzione è il valore massimo in un array contenente sia "k" che "n".

Nota: la max()funzione di Python è la complessità O (n).

Di seguito è riportato un più leggibile, non code-golf versione del codice di cui sopra che ha un caso, unico array di 10-item fornito, per confermare che funziona:

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

Benvenuti in PPCG! Puoi separare in virgola le tue importazioni. Inoltre, non è necessario generare l'array da soli, quindi è possibile rimuovere quella parte del codice (basta avere l'array come parametro per la funzione)
Nathan Merrill

@NathanMerrill Sì, stavo pensando di farlo, ma poi ho pensato che non ti sarebbe piaciuto molto, ma ora che so che davvero non importa, modificherò la mia risposta. Inoltre, grazie per il suggerimento sulla virgola che separa le mie importazioni. Me ne ero completamente dimenticato!
R. Kap,

Altri consigli: hai un sacco di spazi bianchi non necessari (dopo le virgole, tra segni di uguale. Nemmeno tu hai bisogno di una dichiarazione stampata alla fine.
Nathan Merrill

@NathanMerrill Grazie per i suggerimenti! Li terrò a mente mentre faccio più golf nel codice! :)
R. Kap
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.