Una de las preguntas más populares de las estructuras de datos y el algoritmo, formulada principalmente en entrevistas telefónicas.
Una de las preguntas más populares de las estructuras de datos y el algoritmo, formulada principalmente en entrevistas telefónicas.
Respuestas:
Haciendo trampa, y haciendo dos pases al mismo tiempo, en paralelo. Pero no sé si a los reclutadores les gustará esto.
Se puede hacer en una sola lista vinculada, con un buen truco. Dos punteros recorren la lista, uno con doble velocidad. Cuando el rápido llega al final, el otro está a medio camino.
Si no es una lista doblemente enlazada, podría contar y usar una lista, pero eso requiere duplicar su memoria en el peor de los casos, y simplemente no funcionará si la lista es demasiado grande para almacenarla en la memoria.
Una solución simple, casi tonta, es simplemente incrementar el nodo medio cada dos nodos
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;
}
Elaborando sobre la respuesta de Hendrik
Si se trata de una lista doblemente vinculada, itere desde ambos extremos
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;
}
Dado [1, 2, 3] => 2
1, 3
1, 2
2, 2
Dado [1, 2] => 1
1, 2
1, 1
Dado [1] => 1
Dado [] => null
Cree una matriz dinámica, donde cada elemento de la matriz sea un puntero a cada nodo en la lista en orden de desplazamiento, comenzando desde el principio. Cree un número entero, inicializado en 1, que realice un seguimiento de cuántos nodos ha visitado (que se incrementa cada vez que va a un nuevo nodo). Cuando llegue al final, sabrá qué tan grande es la lista y tiene una matriz ordenada de punteros para cada nodo. Finalmente, divida el tamaño de la lista por 2 (y reste 1 para la indexación basada en 0) y busque el puntero que se encuentra en ese índice de la matriz; Si el tamaño de la lista es impar, puede elegir qué elemento devolver (todavía devolveré el primero).
Aquí hay un código Java que hace que el punto se transmita (aunque la idea de una matriz dinámica será un poco inestable). Proporcionaría C / C ++ pero estoy muy oxidado en esa área.
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];
}
¿Se considera la recursión más de un pase?
Recorre la lista hasta el final, pasando un número entero por referencia. Haga una copia local de ese valor en cada nivel para referencia posterior, e incremente el recuento de referencia en la próxima llamada.
En el último nodo, divida el recuento entre dos y trunca / floor () el resultado (si desea que el primer nodo sea el "medio" cuando solo hay dos elementos) o redondee hacia arriba (si desea que el segundo nodo sea la mitad"). Use un índice basado en cero o en uno apropiadamente.
Desenrollado, haga coincidir el recuento de referencias con la copia local (que es el número del nodo). Si es igual, devuelve ese nodo; de lo contrario, devuelve el nodo devuelto por la llamada recursiva.
.
Hay otras formas de hacer esto; algunos de ellos pueden ser menos engorrosos (pensé que vi a alguien decir leerlo en una matriz y usar la longitud de la matriz para determinar las felicitaciones del medio). Pero, francamente, no hay buenas respuestas, porque es una pregunta estúpida de entrevista. Número uno, que todavía usa listas vinculadas ( opinión de apoyo ); Dos, encontrar el nodo intermedio es un ejercicio académico arbitrario sin valor en escenarios de la vida real; Tres, si realmente necesitara conocer el nodo medio, mi lista vinculada expondría un recuento de nodos. Es mucho más fácil mantener esa propiedad que perder el tiempo recorriendo toda la lista cada vez que quiero el nodo central. Y finalmente, cuatro, a cada entrevistador le gustarán o rechazarán diferentes respuestas: lo que un entrevistador piensa que es hábil, otro lo llamará ridículo.
Casi siempre respondo las preguntas de la entrevista con más preguntas. Si recibo una pregunta como esta (nunca la tengo), le preguntaría (1) ¿Qué está almacenando en esta lista vinculada? ¿Existe una estructura más apropiada para acceder de manera eficiente al nodo medio si es realmente necesario hacerlo? ; (2) ¿Cuáles son mis limitaciones? Puedo hacerlo más rápido si la memoria no es un problema (por ejemplo, la respuesta de la matriz), pero si el entrevistador cree que aumentar la memoria es un desperdicio, me molestarán. (3) ¿En qué idioma desarrollaré? Casi todos los idiomas modernos que conozco tienen clases integradas para lidiar con listas vinculadas que hacen innecesario recorrer la lista: ¿por qué reinventar algo que los desarrolladores del lenguaje han ajustado para la eficiencia?
Mediante el uso de 2 punteros. Incremente uno en cada iteración y otro en cada segunda iteración. Cuando el primer puntero apunta al final de la lista vinculada, el segundo puntero apunta al modo medio de la lista vinculada.