LeetCode 25 — Reverse Nodes in K-Group

Undécimo y último problema del patrón Linked List — segundo Hard. Combina 206-reverse-linked-list (reverse) con división en bloques. Es el problema con más manejo manual de punteros del bloque. Si lo dominas, has cerrado linked lists.

Enunciado

Dada la cabeza de una linked list, invierte cada grupo de k nodos consecutivos. Si el último grupo tiene menos de k nodos, déjalo como está.

Ejemplo 1:

Input:  1 → 2 → 3 → 4 → 5, k = 2
Output: 2 → 1 → 4 → 3 → 5  (último grupo "5" se queda)

Ejemplo 2:

Input:  1 → 2 → 3 → 4 → 5, k = 3
Output: 3 → 2 → 1 → 4 → 5

Restricciones:

  • Nodos en [1, 5000].
  • 1 <= k <= n.
  • Tu solución debe ser O(1) memoria extra (no contar la lista output).

Solución — Iterativa con dummy + reverse en bloques (la canónica)

Idea: usar un group_prev (puntero al nodo justo antes del grupo a invertir). Para cada grupo:

  1. Localizar el kth (k-ésimo nodo del grupo). Si no llega → terminar.
  2. Invertir el grupo (mismo patrón que 206-reverse-linked-list).
  3. Reconectar con el resto.
class Solution:
    def reverseKGroup(self, head, k):
        dummy = ListNode(0, head)
        group_prev = dummy
 
        while True:
            kth = self.get_kth(group_prev, k)
            if not kth:
                break
            group_next = kth.next
 
            # Invertir grupo entre (group_prev.next) y kth
            prev = group_next
            curr = group_prev.next
            while curr != group_next:
                tmp = curr.next
                curr.next = prev
                prev = curr
                curr = tmp
 
            # Reconectar
            tmp = group_prev.next                    # antiguo primero, ahora último del grupo
            group_prev.next = kth                    # nuevo primero del grupo
            group_prev = tmp                         # nuevo group_prev para siguiente iteración
 
        return dummy.next
 
    def get_kth(self, node, k):
        while node and k > 0:
            node = node.next
            k -= 1
        return node

Análisis:

  • Tiempo: O(n) — cada nodo se visita una vez para localización y una vez en la inversión.
  • Espacio: O(1).
  • Veredicto: [OK] la canónica.

Por qué dummy node

Para tener un group_prev inicial. Sin dummy, tratar el primer grupo (que cambia la cabeza) requiere caso especial.

Por qué get_kth separado

Es más claro que un contador inline. Devuelve el k-ésimo desde un nodo, o None si no hay suficientes (lo cual indica “último grupo incompleto, no invertir”).


Auto-test

  1. Implementa la solución desde cero. Es el más complejo del patrón — date 1+ hora.
  2. Justifica:
    • Por qué prev = group_next al inicio del while interno.
    • Por qué group_prev = tmp al final (el antiguo primero del grupo es el nuevo group_prev).
  3. Trace mental con 1 → 2 → 3 → 4 → 5, k = 2.

Cierre del patrón Linked List

#ProblemaVarianteIdea distintiva
1206-reverse-linked-listReverse iterativo3 punteros (prev/curr/next)
221-merge-two-sorted-listsMergeDummy + tail
3141-linked-list-cycleFloyd’s tortoise & hareSlow/fast pointers
4143-reorder-listComposición de patronesMid + reverse + merge
519-remove-nth-node-from-end-of-listTwo pointers con offsetk+1 de separación
6138-copy-list-with-random-pointerDeep copyHash old→new
72-add-two-numbersSuma con carryDummy + while con OR
8287-find-the-duplicate-numberFloyd sobre arrayArray como linked list virtual
9146-lru-cacheDiseñoDLL + hash, get/put O(1)
1023-merge-k-sorted-listsK-way mergeHeap o divide-and-conquer
11EsteReverse en bloquesLocalizar + invertir + reconectar

Próximos patrones:

  • Trees (15) — recursión + BFS con deque (que ya viste).
  • Tries (3) — árboles de prefijos.

Conexiones

Estado de progreso personal

  • Leído con comprensión
  • Implementada solución desde cero
  • Trace mental hecho
  • Resuelto en LeetCode con éxito
  • Patrón Linked List cerrado [OK]