Volver a Arrays y Strings
Arrays y Strings

Strings en profundidad

Inmutabilidad, concatenación eficiente, slicing y diferencias clave entre Python y JavaScript.

5 min de lectura

Los strings parecen arreglos de caracteres y en muchos lenguajes se comportan parecido. Pero hay una diferencia crítica que cambia cómo escribes código sobre ellos: en Python, JavaScript, Java y C# los strings son inmutables.

Qué significa inmutable

Una vez que creas un string, no puedes modificarlo. Las operaciones que parecen modificarlo en realidad crean un string nuevo.

s = "hola"
# s[0] = "H"  → TypeError
nuevo = "H" + s[1:]  # crea string nuevo "Hola"
let s = "hola";
// s[0] = "H";  → no falla pero no hace nada
const nuevo = "H" + s.slice(1);  // crea string nuevo "Hola"

Cualquier operación de "modificar" implica copiar todo el contenido a una zona de memoria nueva.

Por qué importa: el bug del loop cuadrático

El error más común con strings: concatenar dentro de un loop.

# MAL: O(n²)
resultado = ""
for palabra in lista_de_palabras:
    resultado += palabra

Cada += no extiende el string viejo. Crea uno nuevo de tamaño len(resultado) + len(palabra) y copia todos los caracteres. Si tienes n palabras de longitud constante, el costo total es 1 + 2 + 3 + ... + n ≈ n²/2.

Para 10.000 palabras, son 50 millones de copias de caracteres. Para 100.000, son 5 mil millones. Tu programa empieza a tardar minutos cuando debería tardar segundos.

La forma correcta en Python

resultado = "".join(lista_de_palabras)

join calcula la longitud total una vez, reserva ese espacio, y copia todo en una pasada. O(n).

La forma correcta en JavaScript

const resultado = lista.join("");

Mismo principio. O(n).

O usar un buffer/array temporal

En ambos lenguajes puedes acumular en una lista/array y unir al final:

partes = []
for palabra in lista_de_palabras:
    partes.append(palabra)
resultado = "".join(partes)
const partes = [];
for (const palabra of lista) {
  partes.push(palabra);
}
const resultado = partes.join("");

Append a lista es O(1) amortizado. Join al final es O(n). Total: O(n).

Slicing en Python

Python tiene slicing nativo poderoso:

s = "hola mundo"
sub = s[0:4]       # "hola"
sub = s[5:]        # "mundo"
sub = s[::-1]      # "odnum aloh" (revertido)
sub = s[::2]       # "hl ud" (cada 2)

Costo: O(j - i) donde i y j son los índices del slice. No es O(1).

s[::-1] para revertir es O(n) y crea un string nuevo. Está bien para casos chicos. Para casos grandes, considerar revertir un arreglo de caracteres.

Slicing en JavaScript

const s = "hola mundo";
const sub1 = s.slice(0, 4);     // "hola"
const sub2 = s.slice(5);        // "mundo"
const sub3 = s.substring(0, 4); // "hola" (similar pero trata negativos distinto)

slice acepta índices negativos (cuentan desde el final). substring no.

Para revertir un string en JS no hay sintaxis nativa. La forma idiomática:

const reverso = s.split("").reverse().join("");

Tres operaciones, todas O(n). Es feo pero funciona.

Comparación de strings

En Python y JS, == compara contenido, no referencia:

"hola" == "hola"  # True
"hola" === "hola"  // true

La comparación es O(n) en el peor caso (recorrer ambos strings hasta encontrar diferencia).

Comparación lexicográfica

Tanto Python como JS comparan strings por orden Unicode de caracteres:

"abc" < "abd"     # True
"abc" < "abcd"    # True (más corto si es prefijo)
"abc" < "abC"     # False, "C" (67) < "c" (99) en Unicode

Para ordenamiento case-insensitive en JS, usar localeCompare:

"Abc".localeCompare("abd", undefined, { sensitivity: "base" });

Operaciones costosas a recordar

OperaciónPythonJSCosto
Largolen(s)s.lengthO(1)
Acceder un carácters[i]s[i] o s.charAt(i)O(1)
Concatenars1 + s2s1 + s2O(n + m)
Subcadenas[i:j]s.slice(i, j)O(j - i)
Buscar carácters.index(c)s.indexOf(c)O(n)
Buscar substrings.find(sub)s.includes(sub)O(n × m) ingenuo
Reemplazars.replace(a, b)s.replace(a, b)O(n)
Lower/Uppers.lower()s.toLowerCase()O(n)
Splits.split(sep)s.split(sep)O(n)

Trucos específicos del lenguaje

Python: f-strings y comparación rápida

nombre = "Martin"
saludo = f"Hola {nombre}"  # más rápido que "Hola " + nombre

in para buscar substring:

"mundo" in "hola mundo"  # True, O(n × m) ingenuo

JavaScript: template literals

const nombre = "Martin";
const saludo = `Hola ${nombre}`;

includes para buscar substring:

"hola mundo".includes("mundo");  // true

La regla para strings en problemas DSA

  1. Si necesitas modificar el string repetidamente, convertilo a arreglo de caracteres (list(s) en Python, s.split("") en JS).
  2. Si solo necesitas leer, trabajá con índices y slicing solo cuando importa.
  3. Nunca concatenes en un loop. Usa join o un buffer.
  4. Asume que cualquier operación de búsqueda o split es O(n) salvo que el lenguaje garantice lo contrario.

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