2014-11-18 3 views
5

Ho avuto un'intervista per un lavoro di sviluppo Jr. e mi ha chiesto di scrivere una procedura che richiede una serie di intarsi e spinge gli zeri alla schiena. Qui ci sono i vincoli (che lui non mi ha detto all'inizio .... Come spesso accade nelle interviste di programmazione, ho imparato i vincoli del problema, mentre ho risolto lol):Buone soluzioni C++ agli interrogatori "Portare tutti gli zeri sul retro dell'array"

  • dovuto farlo a posto; senza la creazione di array temporaneo, nuovi array, ecc
  • Non è necessario conservare l'ordine dei numeri diversi da zero (Vorrei che avrebbe fatto mi ha detto questo, all'inizio)

Setup:

int arr[] = {0, -2, 4, 0, 19, 69}; 
/* Transform arr to {-2, 4, 19, 69, 0, 0} or {69, 4, -2, 19, 0, 0} 
    or anything that pushes all the nonzeros to the back and keeps 
    all the nonzeros in front */ 

La mia risposta:

bool f (int a, int b) {return a == 0;} 
std::sort(arr, arr+sizeof(arr)/sizeof(int), f); 

Quali sono alcune altre buone risposte?

+0

penso che la tua risposta è grande. Cosa ha detto l'intervistatore? –

+2

"Voglio mettere le cose da questa parte e le altre cose da questa parte." Questo è 'std :: partition', a mani basse. Vedi la mia risposta. – PaulMcKenzie

+1

La vostra chiamata a 'std :: sort' non è valida, perché la funzione di confronto non stabilisce un [rigoroso ordine debole] (http://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings). –

risposta

13

Forse l'intervistatore era alla ricerca di questa risposta:

#include <algorithm> 
//... 
std::partition(std::begin(arr), std::end(arr), [](int n) { return n != 0; }); 

Se l'ordine deve essere preservato, quindi std::stable_partition deve essere utilizzato:

#include <algorithm> 
//... 
std::stable_partition(std::begin(arr), std::end(arr), [](int n) { return n != 0; }); 

Per pre C++ 11:

#include <functional> 
#include <algorithm> 
//... 
std::partition(arr, arr + sizeof(arr)/sizeof(int), 
       std::bind1st(std::not_equal_to<int>(), 0)); 

Live Example

Fondamentalmente, se la situazione è che è necessario spostare elementi che soddisfano una condizione su "un lato" di un contenitore, le funzioni dell'algoritmo di partizione dovrebbero essere in alto nell'elenco delle soluzioni da scegliere (se non lo il soluzione da usare).

+0

Non è 'partition' still O (NlogN)? –

+0

@JonathanMee - http://en.cppreference.com/w/cpp/algorithm/partition Per stable_partition, diventa logaritmico nel peggiore dei casi. http://en.cppreference.com/w/cpp/algorithm/stable_partition – PaulMcKenzie

+0

Nella circostanza di un'intervista, potrebbe essere meglio scrivere il lambda come '[] (const int & n) {return n! = 0;} 'o forse anche' [] (const int & n) -> bool {return n;} ', pur essendo pronto a parlare dei meriti relativi di' const int & 'versus just' int'. In entrambi i casi, non è necessario acquisire alcuna variabile. – Edward

2

Un approccio che ordina è O (N * Log N). C'è una soluzione lineare che va in questo modo:

  • Impostare due puntatori - readPtr e writePtr, inizialmente indicando l'inizio della matrice
  • Fare un ciclo che cammina readPtr l'array fino alla fine. Se *readPtr non è zero, copia su *writePtr e avanza entrambi i puntatori; in caso contrario, anticipare solo readPtr.
  • Una volta che readPtr si trova alla fine dell'array, camminare writePtr fino alla fine dell'array, mentre si scrivono gli zeri sugli elementi rimanenti.
+1

Ci sono ancora meno scritture necessarie se si fa quanto segue: Avviare 'readPtr' alla fine e spostarlo all'indietro finché non raggiunge un elemento diverso da zero o' writePtr' (che inizia all'inizio come prima). Se 'readPtr' colpisce' writePtr', hai finito. Altrimenti colpisce un elemento diverso da zero, quindi cammina 'writePtr' in avanti fino a quando non raggiunge un elemento zero o' readPtr'. Se colpisce 'readPtr', hai finito. Altrimenti colpisce un elemento zero, quindi impostalo su '* readPtr', imposta' * writePtr' su zero e ripeti. Solo gli zeri "fuori posizione" e i non zeri devono essere copiati in questo modo. –

+1

Sembra molto simile a 'std :: remove' seguito da' std :: fill'. –

0

Questo è O (n) quindi potrebbe essere quello che sta cercando:

auto arrBegin = begin(arr); 
const auto arrEnd = end(arr); 

for(int i = 0; arrBegin < arrEnd - i; ++arrBegin){ 
    if(*arrBegin == 0){ 
     i++; 
     *arrBegin = *(arrEnd - i); 
    } 
} 
std::fill(arrBegin, arrEnd, 0); 
Problemi correlati