Una delle domande più popolari delle strutture dati e dell'algoritmo, posta principalmente sull'intervista telefonica.
Una delle domande più popolari delle strutture dati e dell'algoritmo, posta principalmente sull'intervista telefonica.
Risposte:
Imbrogliando e facendo due passaggi contemporaneamente, in parallelo. Ma non so se ai reclutatori piacerà questo.
Può essere fatto su un unico elenco collegato, con un bel trucco. Due puntatori viaggiano sull'elenco, uno a doppia velocità. Quando quello veloce raggiunge la fine, l'altro è a metà strada.
Se non è un elenco doppiamente collegato, potresti semplicemente contare e utilizzare un elenco, ma ciò richiede il raddoppio della memoria nel caso peggiore e semplicemente non funzionerà se l'elenco è troppo grande per essere memorizzato.
Una soluzione semplice, quasi sciocca, è semplicemente incrementare il nodo centrale ogni due nodi
function middle(start) {
var middle = start
var nextnode = start
var do_increment = false;
while (nextnode.next != null) {
if (do_increment) {
middle = middle.next;
}
do_increment = !do_increment;
nextnode = nextnode.next;
}
return middle;
}
Elaborazione della risposta di Hendrik
Se è un elenco doppiamente collegato, scorrere da entrambe le estremità
function middle(start, end) {
do_advance_start = false;
while(start !== end && start && end) {
if (do_advance_start) {
start = start.next
}
else {
end = end.prev
}
do_advance_start = !do_advance_start
}
return (start === end) ? start : null;
}
Dato [1, 2, 3] => 2
1, 3
1, 2
2, 2
Dato [1, 2] => 1
1, 2
1, 1
Dato [1] => 1
Dato [] => null
Creare un array dinamico, in cui ogni elemento dell'array è un puntatore a ciascun nodo nell'elenco in ordine di movimento, a partire dall'inizio. Crea un numero intero, inizializzato su 1, che tenga traccia di quanti nodi hai visitato (che aumenta ogni volta che vai su un nuovo nodo). Quando arrivi alla fine, sai quanto è grande l'elenco e hai un array ordinato di puntatori per ciascun nodo. Infine, dividi la dimensione dell'elenco per 2 (e sottrai 1 per l'indicizzazione basata su 0) e recupera il puntatore contenuto in quell'indice dell'array; se la dimensione dell'elenco è dispari, puoi scegliere quale elemento restituire (restituirò comunque il primo).
Ecco un po 'di codice Java che fa capire il punto (anche se l'idea di un array dinamico sarà un po' traballante). Fornirei C / C ++ ma sono molto arrugginito in quella zona.
public Node getMiddleNode(List<Node> nodes){
int size = 1;
//add code to dynamically increase size if at capacity after adding
Node[] pointers = new Node[10];
for (int i = 0; i < nodes.size(); i++){
//remember to dynamically allocate more space if needed
pointers[i] = nodes.get(i);
size++;
}
return pointers[(size - 1)/2];
}
La ricorsione è considerata più di un passaggio?
Attraversa l'elenco fino alla fine, passando un numero intero per riferimento. Crea una copia locale di quel valore a ciascun livello per riferimento futuro e incrementa il conteggio di riferimento andando alla chiamata successiva.
Nell'ultimo nodo, dividere il conteggio per due e troncare / floor () il risultato (se si desidera che il primo nodo sia "centrale" quando sono presenti solo due elementi) o arrotondare per eccesso (se si desidera che il secondo nodo sia la metà"). Utilizzare un indice a base zero o uno in modo appropriato.
Svolgendo, abbina il conteggio di riferimento alla copia locale (che è il numero del nodo). Se uguale, restituisce quel nodo; else restituisce il nodo restituito dalla chiamata ricorsiva.
.
Ci sono altri modi per farlo; alcuni potrebbero essere meno ingombranti (pensavo di aver visto qualcuno dire leggerlo in un array e usare la lunghezza dell'array per determinare i kudos di mezzo). Ma francamente, non ci sono buone risposte, perché è una domanda stupida da intervista. Numero uno, che utilizza ancora elenchi collegati ( parere di supporto ); Secondo, trovare il nodo centrale è un esercizio accademico arbitrario senza valore negli scenari della vita reale; Tre, se avessi davvero bisogno di conoscere il nodo centrale, la mia lista collegata avrebbe rivelato il conteggio dei nodi. È molto più facile mantenere quella proprietà che perdere tempo attraversando l'intero elenco ogni volta che voglio il nodo centrale. E infine, quattro, a ogni intervistatore piacerà o rifiuterà risposte diverse: ciò che un intervistatore ritiene slick, un altro lo chiamerà ridicolo.
Quasi sempre rispondo alle domande dell'intervista con più domande. Se ricevo una domanda come questa (non l'ho mai fatto), chiederei (1) Cosa stai memorizzando in questo elenco collegato ed esiste una struttura più appropriata per accedere in modo efficiente al nodo centrale se è davvero necessario farlo ; (2) Quali sono i miei vincoli? Posso renderlo più veloce se la memoria non è un problema (ad es. La risposta dell'array), ma se l'intervistatore ritiene che caricare la memoria sia dispendioso, mi verrà oscurato. (3) In che lingua svilupperò? Quasi ogni linguaggio moderno che conosco ha classi integrate per gestire elenchi collegati che rendono superfluo attraversare l'elenco: perché reinventare qualcosa che è stato messo a punto per l'efficienza dagli sviluppatori del linguaggio?
Usando 2 puntatori. Incrementa uno ad ogni iterazione e l'altro ad ogni seconda iterazione. Quando il 1 ° puntatore punta alla fine dell'elenco collegato, il 2 ° puntatore punta alla modalità centrale dell'elenco collegato.