Volver a Arrays y Strings
Arrays y Strings

Operaciones in-place

Cómo modificar un arreglo sin crear uno nuevo. La técnica detrás de la mayoría de problemas O(1) en espacio.

4 min de lectura

"In-place" significa modificar la estructura original sin asignar memoria proporcional al input. Es la base de muchas optimizaciones de espacio, y es lo que te van a pedir cuando un problema diga "resuelve sin usar memoria extra" o "O(1) espacio adicional".

El swap como primitivo

La operación atómica de in-place es el swap: intercambiar dos elementos sin variables auxiliares (más allá de una temporal).

arr[i], arr[j] = arr[j], arr[i]

En JavaScript moderno también funciona con destructuring:

[arr[i], arr[j]] = [arr[j], arr[i]];

O con variable temporal:

const tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;

Swap es O(1) tiempo y O(1) espacio. Casi todo algoritmo in-place se reduce a una secuencia de swaps.

Patrones in-place clásicos

1. Revertir un arreglo (dos punteros)

def revertir(arr):
    izq, der = 0, len(arr) - 1
    while izq < der:
        arr[izq], arr[der] = arr[der], arr[izq]
        izq += 1
        der -= 1

Los punteros se acercan al medio. Cada paso swappa una posición. O(n) tiempo, O(1) espacio.

2. Mover ceros al final

Problema clásico: dado un arreglo, mover todos los ceros al final manteniendo el orden relativo del resto, sin crear arreglo nuevo.

def mover_ceros(arr):
    siguiente = 0
    for i in range(len(arr)):
        if arr[i] != 0:
            arr[siguiente], arr[i] = arr[i], arr[siguiente]
            siguiente += 1

siguiente marca dónde va el próximo no-cero. Una sola pasada. O(n) tiempo, O(1) espacio.

3. Eliminar duplicados en arreglo ordenado

Dado un arreglo ordenado, deja solo elementos únicos al principio y devuelve la nueva longitud.

def eliminar_duplicados(arr):
    if not arr:
        return 0
    escribir = 1
    for leer in range(1, len(arr)):
        if arr[leer] != arr[leer - 1]:
            arr[escribir] = arr[leer]
            escribir += 1
    return escribir

Dos punteros: uno lee, uno escribe. Cuando el lector encuentra un valor nuevo, lo copia a la posición de escribir. O(n) tiempo, O(1) espacio.

4. Rotar un arreglo k posiciones

Problema clásico: rotar [1,2,3,4,5,6,7] 3 posiciones a la derecha → [5,6,7,1,2,3,4].

Truco de los tres reversos:

def rotar(arr, k):
    n = len(arr)
    k = k % n
    # 1. Revertir todo
    revertir(arr, 0, n - 1)
    # 2. Revertir los primeros k
    revertir(arr, 0, k - 1)
    # 3. Revertir el resto
    revertir(arr, k, n - 1)

def revertir(arr, i, j):
    while i < j:
        arr[i], arr[j] = arr[j], arr[i]
        i += 1
        j -= 1

Tres pasadas pero todas O(n). Total: O(n) tiempo, O(1) espacio.

La trampa: in-place no siempre es óptimo

Hacer todo in-place puede complicar el código sin ganancia real. Si el arreglo tiene 100 elementos, gastar 100 elementos más de memoria no cambia nada. Si tiene 100 millones, sí importa.

Cuándo conviene in-place:

  • El input es grande (millones+).
  • El sistema tiene memoria limitada.
  • El problema lo pide explícitamente.

Cuándo NO conviene:

  • El input es chico y la legibilidad importa más.
  • La versión in-place introduce bugs sutiles (índices, swap parcial).
  • En entrevista, si la versión no-in-place es claramente correcta y la in-place no, presenta la primera y mencioná la segunda como mejora.

Errores típicos en in-place

Iterar y modificar al mismo tiempo

Si modificas un arreglo mientras lo recorres, puedes saltarte elementos o procesar el mismo dos veces.

# MAL: skip de elementos
for i in range(len(arr)):
    if arr[i] == 0:
        arr.pop(i)  # los siguientes se mueven a la izquierda

Después del pop, el siguiente elemento ahora está en la posición i, pero el loop avanza a i+1. Te lo salteas.

Solución 1: iterar de derecha a izquierda.

for i in range(len(arr) - 1, -1, -1):
    if arr[i] == 0:
        arr.pop(i)

Solución 2: usar dos punteros y no eliminar, sobrescribir.

Mutar parámetros y devolver el mismo arreglo

Si la función modifica arr y devuelve arr, el código que llama puede confundirse: ¿modifiqué el original o trabajo con uno nuevo?

def revertir(arr):
    arr.reverse()
    return arr

original = [1, 2, 3]
nuevo = revertir(original)
# Sorpresa: original también está revertido

Si tu función es in-place, deja clara la convención: o no devuelvas nada (la mutación es el resultado), o documentalo explícitamente.

En resumen

In-place es una técnica de optimización de memoria, no una bala de plata. Si te lo piden explícitamente, usalo. Si no, balanceá legibilidad vs eficiencia según el contexto. Y siempre que modifiques al iterar, piensa dos veces.

Inicia sesión para guardar el progreso de esta lección.