Blog en español

Listas enlazadas en Python: guía para entrevistas

19 de mayo de 202620 min de lectura
Listas enlazadas en Python: guía para entrevistas

Domina las listas enlazadas en Python con patrones, plantillas y errores clave para entrevistas. Aprende a resolverlas mejor y más rápido.

La mayoría de los candidatos que tienen problemas con las listas enlazadas en una entrevista no fallan porque no conozcan el concepto. Saben que una lista enlazada es una cadena de nodos en la que cada nodo contiene un valor y un puntero al siguiente. El problema es que una entrevista sobre listas enlazadas en Python le pide hacer algo con ese concepto bajo presión de tiempo: escribir una clase `ListNode` desde cero, invertir la lista sin perder ninguna referencia, detectar un ciclo antes de que se agote la paciencia del entrevistador. Esa es una habilidad distinta a conocer la definición, y la mayoría de los recursos de preparación tratan ambas cosas como si fueran lo mismo.

Esta guía es el camino más corto desde comprender la estructura de nodos hasta ejecutar los patrones que los entrevistadores repiten de verdad. No cubrirá todos los posibles problemas de listas enlazadas. Cubrirá los que importan, la plantilla que se sostiene bajo presión y los errores que rompen en silencio soluciones que, por lo demás, serían correctas.

Qué es realmente una lista enlazada en Python y por qué los entrevistadores siguen preguntando por ella

Deje de pensar en índices y empiece a pensar en nodos

Los arrays le dan posiciones. Pide el índice 3 y obtiene el valor en el índice 3: tiempo constante, sin necesidad de navegar. Las listas enlazadas le dan referencias. Empieza en la cabeza y sigue los punteros hasta llegar a lo que necesita. Esa diferencia no es un detalle sin importancia. Es exactamente la razón por la que los entrevistadores sacan las listas enlazadas en las entrevistas.

Cuando un entrevistador le pide comparar ambas estructuras, está evaluando si entiende por qué existe el intercambio. Los arrays se almacenan en memoria contigua, lo que hace que el acceso aleatorio sea rápido y que el comportamiento de caché sea predecible. Las listas enlazadas dispersan los nodos por la memoria, lo que hace más lenta la navegación para acceder aleatoriamente, pero permite que la inserción y eliminación en posiciones arbitrarias sea O(1) una vez que tiene el puntero correcto, porque solo está reencaminando referencias y no desplazando elementos. Según las notas sobre estructuras de datos de MIT OpenCourseWare, estas diferencias de complejidad temporal derivan directamente del modelo de memoria subyacente, no de decisiones de implementación a nivel de lenguaje.

La pregunta de entrevista “¿cuándo usaría una lista enlazada en lugar de un array?” tiene una respuesta real: cuando hace inserciones y eliminaciones frecuentes en medio de una secuencia y no necesita acceso aleatorio. La pregunta de seguimiento honesta es que, en la mayor parte del código de producción en Python, `collections.deque` resuelve esto mejor que una lista enlazada hecha a mano; pero la entrevista evalúa si entiende el intercambio, no si la usaría en producción.

Cómo se ve esto en la práctica

Recorrer un array de tres nodos en Python es una línea: `arr[2]`. Recorrer una lista enlazada de tres nodos requiere tres saltos de puntero: `head`, luego `head.next`, luego `head.next.next`. Se siente más lento porque, para acceso aleatorio, lo es. Pero ahora imagine que quiere insertar un nodo entre las posiciones 1 y 2. En el array, desplaza todos los elementos posteriores a la posición 1 una casilla a la derecha: O(n). En la lista enlazada, cambia dos punteros: O(1) una vez que está en el nodo correcto.

El momento en que esa diferencia me quedó clara fue cuando dejé de preguntar “¿qué índice es este?” y empecé a preguntar “¿a qué apunta este nodo?”. La lista dejó de parecer un array roto y empezó a parecer una cadena en la que la forma de la cadena es la estructura. Una vez que la ve así, manipular punteros deja de sentirse arbitrario.

Escriba una plantilla de ListNode que realmente pueda usar bajo presión de entrevista

El constructor mínimo que hace el trabajo sin complicarse

La clase `ListNode` que escriba en una entrevista debe ser inmediatamente legible y tardar menos de treinta segundos en teclearla. Esta es la versión que funciona:

Eso es todo. Los valores predeterminados `val=0` y `next=None` le permiten crear un nodo solo con un valor (`ListNode(5)`) o encadenarlos en línea (`ListNode(1, ListNode(2, ListNode(3)))`). Ambos patrones aparecen constantemente. Los valores por defecto mantienen el constructor flexible sin añadir carga cognitiva.

Algunos candidatos añaden un puntero `prev` para variantes de listas doblemente enlazadas. No lo añada salvo que el problema lo pida explícitamente: los atributos extra que no necesitaba indican ruido, no minuciosidad.

slots es un buen detalle, no el punto central

Añadir `__slots__ = ('val', 'next')` a la declaración de la clase le dice a Python que use una distribución de memoria de tamaño fijo en lugar de un `__dict__` por instancia. Para una `ListNode` que se instancia miles de veces, reduce de forma medible la sobrecarga de memoria. La documentación de Python sobre `__slots__` explica la mecánica en detalle.

En una entrevista, mencionar `__slots__` es una señal razonable de que usted entiende el modelo de objetos de Python. Incluirlo en su plantilla sin que se lo pidan es otra cuestión: añade una línea que probablemente el entrevistador le pedirá explicar, y si no puede hacerlo con claridad, queda peor que si lo omite. Conózcalo. Úselo si el entrevistador pregunta por optimización de memoria. No abra con ello.

Cómo se ve esto en la práctica

Construcción y recorrido de una lista de tres nodos con esta plantilla:

El patrón de recorrido — `current = head`, avanzar con `current = current.next`, detenerse cuando `current` es `None` — es la base de casi todas las soluciones con listas enlazadas que escribirá. Interiorice este bucle antes de tocar cualquier otra cosa.

Aprenda a recorrer, insertar, eliminar e invertir antes de tocar los patrones avanzados

Recorrer es la parte aburrida que salva todas las demás soluciones

La preparación de entrevistas sobre listas enlazadas que salta directamente a punteros rápidos/lentos o a detección de ciclos está construyendo sobre arena. Recorrer no es un calentamiento: es la operación subyacente de la que dependen todos los demás patrones. Si pierde de vista `current` a mitad del recorrido, pierde la lista. No hay un índice al que volver.

El bucle de recorrido anterior es el patrón completo. La única variación que merece la pena conocer es el recorrido con dos punteros, en el que mantiene `prev` y `current` simultáneamente, algo que necesitará para eliminar e invertir. Cójale soltura a ambos antes de seguir.

El error de un solo puntero que arruina las eliminaciones

El fallo clásico al eliminar: un candidato escribe `current.next = current.next.next` y luego intenta volver a usar `current.next`, sin darse cuenta de que esa referencia ya se perdió. La solución siempre es la misma: guarde lo que necesite antes de reencaminar nada.

No es un error sutil. Aparece en casi todas las sesiones con listas enlazadas en las que el candidato va con prisa y deja de narrar el estado de sus punteros. La solución es narrarlo en voz alta: “Estoy guardando `next` antes de reasignar”.

Cómo se ve esto en la práctica

La reversión iterativa es la operación individual más importante que debe interiorizar. Recórrela paso a paso:

En cada paso, `next_node` se guarda antes de sobrescribir `current.next`. Esa sola línea —guardar la referencia hacia delante— es la diferencia entre una inversión limpia y una lista que desaparece en `None`. En cuanto interioriza por qué es necesario ese guardado, inserción y eliminación empiezan a tener el mismo sentido.

Los cinco patrones de listas enlazadas que los entrevistadores prueban una y otra vez

Invertir, fusionar, punteros rápidos/lentos, nodo ficticio, ciclo: todo el juego en cinco movimientos

Las preguntas de entrevistas sobre listas enlazadas en Python parecen diversas en la superficie. No lo son. Casi todas las preguntas que encontrará en una entrevista junior o de nivel medio son variantes de cinco patrones subyacentes: invertir, fusionar dos listas ordenadas, punteros rápidos/lentos, nodo ficticio y detección de ciclos. Una vez que ve el patrón debajo del enunciado del problema, está eligiendo una herramienta de un pequeño conjunto en lugar de resolver desde cero.

No es exageración. Una revisión de los problemas de listas enlazadas que aparecen con mayor frecuencia en las principales plataformas de programación confirma que estas cinco categorías representan la gran mayoría de lo que se pregunta. Los problemas curados de LeetCode y la hoja de ruta de NeetCode muestran el mismo grupo de problemas cuando se filtran por frecuencia de listas enlazadas.

Cómo se ve esto en la práctica

Cada patrón se mapea directamente a un problema representativo:

  • Invertir → Reverse Linked List (LeetCode 206). El enfoque iterativo de tres punteros anterior es la plantilla.
  • Fusionar → Merge Two Sorted Lists (LeetCode 21). Dos punteros recorriendo ambas listas, con un nodo ficticio al principio.
  • Punteros rápidos/lentos → Middle of the Linked List (LeetCode 876), además de detección de ciclos (LeetCode 141).
  • Nodo ficticio → Remove Nth Node From End (LeetCode 19), Merge Two Sorted Lists.
  • Detección de ciclos → Linked List Cycle (LeetCode 141), Linked List Cycle II (LeetCode 142).

Cuando se le presente un problema nuevo, la primera pregunta no es “¿cómo lo resuelvo?” Es “¿a cuál de estos cinco patrones se parece?”. Ese simple cambio de enfoque reduce el tiempo que pasa mirando un editor en blanco.

Por qué reconocer patrones vence a memorizar respuestas

Los entrevistadores de la mayoría de las empresas no están comprobando si usted memorizó una solución específica. Están observando si puede identificar la estructura del problema con suficiente rapidez como para empezar a tomar decisiones correctas. Un candidato que dice “esto parece un problema de punteros rápidos/lentos porque necesitamos encontrar una posición relativa al final sin conocer la longitud” suena mejor preparado que uno que produce en silencio el código correcto sin explicar la elección. El reconocimiento de patrones es la señal.

Use un nodo ficticio cuando los casos de cabeza, de otro modo, le harían perder tiempo

La idea es dejar de tratar la cabeza como si fuera especial

Los nodos ficticios existen por una razón: la cabeza de la lista es un caso especial en un número sorprendente de problemas, y manejarla con ramas explícitas (`if head is None`, `if vamos a borrar la cabeza`, `if el primer nodo es el objetivo de la fusión`) añade complejidad que no tiene nada que ver con la lógica principal.

Un nodo ficticio es una `ListNode(0)` de usar y tirar cuyo puntero `next` comienza en `head`. Ahora su algoritmo nunca tiene que tratar el primer nodo real de forma diferente al resto, porque siempre hay un nodo antes de él.

Cómo se ve esto en la práctica

Fusionar dos listas ordenadas sin un nodo ficticio requiere una comprobación separada para establecer qué lista proporciona la cabeza inicial. Con un nodo ficticio:

El `dummy.next` al final es la verdadera cabeza de la lista fusionada. Sin el nodo ficticio, necesitaría una condición antes del bucle para averiguar qué nodo inicia el resultado. Con él, el bucle maneja todos los casos de la misma manera. En una resolución real, esto elimina tres comprobaciones separadas de casos límite del código, el tipo de comprobaciones que parecen seguridad pero en realidad indican que la solución no está limpia.

Los punteros rápidos y lentos resuelven más que preguntas sobre el nodo medio

El mismo truco encuentra el medio, detecta ciclos y prepara la eliminación del n ésimo desde el final

Los punteros rápidos y lentos funcionan porque dos punteros que avanzan a distintas velocidades por la misma lista crean una relación de distancia predecible. Mueva `fast` dos pasos por cada un paso de `slow`, y cuando `fast` llegue al final, `slow` estará en el medio. Si ambos siguen moviéndose en un ciclo, acabarán encontrándose. Si empieza `fast` n pasos por delante de `slow`, cuando `fast` llegue a `None`, `slow` estará n nodos desde el final.

Esa es una sola idea estructural con tres aplicaciones directas. La matemática subyacente es la misma en cada caso.

Cómo se ve esto en la práctica

Nodo medio:

Detección de ciclos (algoritmo de Floyd):

Eliminar el n-ésimo desde el final: Empiece `fast` n+1 pasos por delante de `slow` (ambos comenzando en un nodo ficticio) y luego avance ambos un paso cada vez. Cuando `fast` sea `None`, `slow.next` es el nodo que debe eliminarse.

La condición del bucle `while fast and fast.next` es la misma en los tres casos. Esa consistencia es la clave: una vez que la escribe una vez, la escribe siempre.

Por qué los candidatos complican en exceso este patrón

El error más común es intentar reconstruir la solución de memoria en lugar de seguir la distancia entre punteros paso a paso. Los candidatos que memorizaron el código de detección de ciclos pero no interiorizaron por qué se encuentran los punteros se bloquean cuando el entrevistador pregunta “¿qué pasa si el ciclo empieza en el tercer nodo?”. Trabaje en papel un ejemplo de cinco nodos, etiquetando la posición de cada puntero en cada paso. El patrón se vuelve obvio de inmediato y sigue siéndolo bajo presión.

Según CLRS (Introduction to Algorithms), la prueba de corrección de la detección de ciclos de Floyd se deriva directamente de la aritmética modular de dos punteros en un bucle; entender eso hace que el algoritmo sea memorable en lugar de arbitrario.

Elija los problemas de práctica adecuados en lugar de machacar problemas aleatorios

Empiece con victorias fáciles y luego pase a los problemas que realmente combinan patrones

Machacar problemas aleatorios produce resultados aleatorios. Una escalera de práctica estructurada produce reconocimiento de patrones transferible. Para un candidato junior que se prepara para una entrevista sobre listas enlazadas, el orden importa más que el volumen.

Empiece con el recorrido y la manipulación básica: invierta una lista de forma iterativa y luego de forma recursiva. Después pase a problemas que introducen un segundo patrón: fusionar dos listas ordenadas (fusión + nodo ficticio), encontrar el medio (rápidos/lentos), detectar un ciclo (rápidos/lentos con comprobación de igualdad). Cuando eso le resulte automático, pase a problemas que combinan dos patrones: eliminar el n-ésimo desde el final (nodo ficticio + separación entre punteros rápidos/lentos), comprobar si una lista es palíndromo (rápidos/lentos para encontrar el medio + invertir la segunda mitad), reordenar la lista (medio + inversión + fusión).

Solo después de esa capa de combinación debería intentar reverse nodes in k-group o LRU cache; esos problemas asumen que ha interiorizado por completo los patrones más simples.

Cómo se ve esto en la práctica

Una escalera de estudio compacta para candidatos junior, en orden:

  • Reverse Linked List (LeetCode 206) — iterativo y recursivo
  • Merge Two Sorted Lists (LeetCode 21) — base con nodo ficticio
  • Middle of the Linked List (LeetCode 876) — base de rápidos/lentos
  • Linked List Cycle (LeetCode 141) — detección de ciclos
  • Remove Nth Node From End (LeetCode 19) — nodo ficticio + separación entre punteros
  • Palindrome Linked List (LeetCode 234) — combinación de medio + inversión
  • Reorder List (LeetCode 143) — medio + inversión + fusión todo a la vez

Siete problemas, en ese orden, prestando atención deliberada a qué patrón enseña cada uno. Esa es una semana de preparación más útil que treinta problemas aleatorios resueltos en orden aleatorio. La ruta Blind 75 de NeetCode clasifica estos problemas en una secuencia similar exactamente por esa razón.

Evite los errores de Python que arruinan buenas soluciones de listas enlazadas

Perder una referencia es el error pequeño más caro que puede cometer

Los problemas de listas enlazadas en Python castigan más que ningún otro un error: reasignar un puntero antes de guardar a qué apuntaba. La lista no lanza un error. Simplemente se truncará en silencio, y la salida será incorrecta de una forma difícil de rastrear si no está narrando el estado de los punteros en voz alta.

La regla es mecánica: antes de cambiar `current.next`, guarde `current.next` en una variable. Antes de mover `current`, guarde hacia dónde va. Esto no es programación defensiva: es el orden correcto de ejecución para manipular punteros.

Las comprobaciones de None no son un adorno opcional

Una lista vacía (`head is None`) y una lista de un solo nodo (`head.next is None`) son los dos casos límite que rompen más soluciones. Un bucle de recorrido que asume al menos dos nodos lanzará un `AttributeError` con una entrada de un solo nodo. Una eliminación que asume que el objetivo no es la cabeza devolverá una lista corrupta. Mencionar estos casos en voz alta antes de escribir la solución le indica al entrevistador que ha pensado el problema a fondo; no es pedantería, es oficio de entrevista.

Cómo se ve esto en la práctica

Aquí tiene una eliminación incorrecta y después la versión corregida:

El nodo ficticio elimina el caso límite de borrar la cabeza. El retorno temprano tras la eliminación evita avanzar dos veces. No son trucos ingeniosos: son los patrones estándar que impiden que las soluciones de listas enlazadas en Python se rompan con las entradas que los entrevistadores siempre prueban primero.

Cómo Verve AI puede ayudarle a aprobar su entrevista técnica con listas enlazadas en Python

El problema estructural al que apunta esta guía —conocer el patrón pero perder el hilo cuando tiene que explicarlo en vivo— no se resuelve leyendo. Se resuelve haciéndolo en voz alta, bajo algo que se parezca a presión real, hasta que la narración se vuelva automática.

Verve AI Coding Copilot está diseñado exactamente para ese vacío. Lee su pantalla mientras trabaja en un problema en LeetCode, HackerRank o CodeSignal, y responde a lo que realmente está escribiendo, no a una petición genérica. Cuando su lógica de punteros se desvía o el manejo de casos límite queda incompleto, Verve AI Coding Copilot señala el problema concreto en contexto, no una pista genérica. La función Secondary Copilot le mantiene enfocado en un solo problema sin perder el lugar cuando se atasca y necesita pensar el estado de los punteros paso a paso. Y como permanece invisible durante rondas técnicas en vivo, el apoyo no se detiene cuando empieza la entrevista. Para candidatos que siguen la escalera de práctica de esta guía, Verve AI Coding Copilot convierte el trabajo en solitario en algo más parecido a una repetición guiada, que es donde realmente se construye el reconocimiento de patrones.

Preguntas frecuentes

P: ¿Qué es una lista enlazada en Python y en qué se diferencia de un array en términos de entrevista?

Una lista enlazada es una secuencia de nodos en la que cada nodo contiene un valor y una referencia al siguiente nodo. A diferencia de un array, no hay un bloque de memoria contiguo ni acceso basado en índices: usted navega siguiendo punteros desde la cabeza. En términos de entrevista, la diferencia clave está en la complejidad temporal: los arrays ofrecen acceso aleatorio O(1) pero inserción/eliminación O(n) en medio; las listas enlazadas ofrecen inserción/eliminación O(1) una vez que tiene el puntero, pero recorrido O(n) para encontrar una posición.

P: ¿Cuáles son los patrones básicos de listas enlazadas que los entrevistadores suelen evaluar más a menudo?

Los cinco patrones que cubren la gran mayoría de las preguntas de entrevista son: invertir (iterativo de tres punteros), fusionar dos listas ordenadas (dos punteros + nodo ficticio), punteros rápidos/lentos (medio, ciclo, n-ésimo desde el final), nodo ficticio (elimina casos límite de la cabeza) y detección de ciclos (algoritmo de Floyd). La mayoría de los problemas son disfraces nuevos de una de estas cinco mecánicas.

P: ¿Cómo se escribe una clase `ListNode` básica y cómo se recorre, inserta, elimina e invierte una lista en Python?

La clase mínima es `class ListNode: def __init__(self, val=0, next=None)`. El recorrido usa `current = head; while current: current = current.next`. La eliminación guarda `current.next` antes de reencaminar. La inversión usa tres punteros —`prev`, `current`, `next_node`— avanzando en el orden correcto para no perder ninguna referencia. El patrón iterativo de inversión de la Sección 3 cubre la secuencia exacta.

P: ¿Cuándo debe usar un nodo ficticio y cómo simplifica los problemas de eliminación de la cabeza y de fusión?

Use un nodo ficticio siempre que la cabeza de la lista pueda cambiar o desaparecer: eliminación de la cabeza, fusión, eliminar el n-ésimo desde el final. El nodo ficticio se sitúa antes de la cabeza real, de modo que su algoritmo trata todos los nodos de forma uniforme. Usted devuelve `dummy.next` al final en lugar de seguir qué nodo se convirtió en la nueva cabeza. Elimina la ramificación condicional para el primer nodo sin añadir complejidad lógica.

P: ¿Cómo se resuelven los problemas de nodo medio, detección de ciclos y eliminación del n-ésimo desde el final con punteros rápidos/lentos?

Para el nodo medio, avance `slow` un paso y `fast` dos pasos hasta que `fast` o `fast.next` sea `None`; `slow` estará en el medio. Para detección de ciclos, el mismo movimiento; si `slow == fast` en algún momento, hay un ciclo. Para eliminar el n-ésimo desde el final, coloque `fast` n+1 pasos por delante de `slow` (ambos en un nodo ficticio) y luego avance ambos un paso cada vez; cuando `fast` sea `None`, `slow.next` es el nodo objetivo.

P: ¿Qué casos límite debería mencionar siempre en una respuesta de entrevista sobre listas enlazadas?

Mencione siempre: lista vacía (`head is None`), lista de un solo nodo, lista de dos nodos (especialmente para inversión y fusión), y el caso en que el nodo objetivo es la cabeza. Mencionarlos antes de escribir código demuestra que ha pensado el problema. Omitirlos y que el entrevistador encuentre un caso de prueba fallido en una de estas entradas es la forma más habitual de que una solución correcta pierda puntos.

P: ¿Qué problemas de listas enlazadas debería practicar primero un candidato junior para ganar confianza en entrevistas?

En este orden: Reverse Linked List, Merge Two Sorted Lists, Middle of the Linked List, Linked List Cycle, Remove Nth Node From End, Palindrome Linked List, Reorder List. Cada problema de esa secuencia enseña un patrón concreto o una combinación de patrones. Resolverlos en orden construye la base antes de introducir problemas que combinan varias técnicas.

P: ¿Cómo explica con claridad a un entrevistador los intercambios de una lista enlazada y la manipulación de punteros?

Empiece por el modelo de memoria: los arrays usan memoria contigua para acceso O(1), las listas enlazadas usan nodos dispersos para inserción/eliminación O(1) en una posición conocida. Luego sea honesto sobre la limitación práctica: el recorrido es O(n), y en Python `deque` resuelve mejor la mayoría de los casos de uso en producción. Para la manipulación de punteros, narre el estado de los punteros en voz alta en cada paso: “Estoy guardando `next` antes de reencaminar `current.next`”. Esa narración es lo que distingue a un candidato que entiende la mecánica de uno que memorizó el código.

---

No necesitaba una enciclopedia de listas enlazadas. Necesitaba un manual orientado a Python que mantuviera los punteros en orden desde el primer constructor de nodo hasta el último caso límite. Los patrones de esta guía —invertir, fusionar, rápidos/lentos, nodo ficticio, detección de ciclos— son los mismos que aparecen en todas las principales plataformas de entrevistas, en todas las variantes y en todos los niveles. Trabaje la escalera de práctica en orden, narre siempre en voz alta el estado de sus punteros y revise los casos límite antes de escribir una sola línea de solución. La confianza en entrevistas sobre listas enlazadas no viene de haber visto todos los problemas posibles. Viene de haber interiorizado un pequeño conjunto de mecánicas lo bastante bien como para que los problemas nuevos le resulten familiares antes de haber terminado de leerlos.

CW

Cameron Wu

Contenido