<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Axel Espinosa</title>
    <description>The latest articles on DEV Community by Axel Espinosa (@fromchiapasdev).</description>
    <link>https://dev.to/fromchiapasdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186583%2F9cef57b1-206b-4316-9880-0fe5907f987f.jpeg</url>
      <title>DEV Community: Axel Espinosa</title>
      <link>https://dev.to/fromchiapasdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fromchiapasdev"/>
    <language>en</language>
    <item>
      <title>Qué es un hashmap y por qué es tan rápido</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:19:59 +0000</pubDate>
      <link>https://dev.to/aws/que-es-un-hashmap-y-por-que-es-tan-rapido-1im2</link>
      <guid>https://dev.to/aws/que-es-un-hashmap-y-por-que-es-tan-rapido-1im2</guid>
      <description>&lt;p&gt;Cuando escribes &lt;code&gt;localStorage.getItem("token")&lt;/code&gt;, el navegador busca por clave de forma directa, sin recorrer todo. Esa idea de "dame el valor de esta clave" sin pasar por toda la estructura es lo que hace un hashmap.&lt;/p&gt;

&lt;p&gt;En los artículos anteriores vimos &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;arrays&lt;/a&gt; y &lt;a href="https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd"&gt;strings&lt;/a&gt;. Ambos son secuencias: para encontrar algo, recorres elemento por elemento, y eso es O(n). Los hashmaps resuelven ese problema de una forma bastante elegante.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6x7w1yjap3um0ypoh325.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6x7w1yjap3um0ypoh325.png" alt="Cosas cotidianas que son hashmaps por debajo: Map de JS, dicts de Python, HTTP headers, localStorage" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lo que encontrarás en este artículo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué es un hashmap y por qué importa&lt;/li&gt;
&lt;li&gt;Qué hace una función hash y qué propiedades tiene&lt;/li&gt;
&lt;li&gt;Cómo funciona por debajo: buckets, colisiones y cómo se resuelven&lt;/li&gt;
&lt;li&gt;Load factor y rehashing&lt;/li&gt;
&lt;li&gt;Big O y por qué el O(1) tiene un asterisco&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. ¿Qué es un hashmap?
&lt;/h2&gt;

&lt;p&gt;Un hashmap almacena pares clave-valor. Tú le das una clave, él te devuelve el valor asociado.&lt;/p&gt;

&lt;p&gt;Piénsalo como un casillero con etiquetas. Cada casillero tiene una etiqueta (la clave) y adentro hay algo guardado (el valor). Para abrir el casillero de &lt;code&gt;"token"&lt;/code&gt;, no revisas todos los casilleros uno por uno, vas directo al que tiene esa etiqueta.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsss8xlity3evwmg122o0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsss8xlity3evwmg122o0.png" alt="Hashmap como tabla de dos columnas: clave y valor" width="799" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eso es lo que diferencia a un hashmap de un array. Los arrays buscan por índice numérico: &lt;code&gt;array[0]&lt;/code&gt;, &lt;code&gt;array[5]&lt;/code&gt;. Los hashmaps buscan por cualquier clave: &lt;code&gt;"nombre"&lt;/code&gt;, &lt;code&gt;"email"&lt;/code&gt;, &lt;code&gt;"token"&lt;/code&gt;. Y el tiempo de búsqueda es prácticamente el mismo sin importar cuántos pares haya guardados.&lt;/p&gt;

&lt;p&gt;En distintos lenguajes lo conoces con nombres diferentes, aunque todos hacen lo mismo:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lenguaje&lt;/th&gt;
&lt;th&gt;Nombre&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dict&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;&lt;code&gt;HashMap&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;&lt;code&gt;map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En JavaScript se usa así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;mapa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;mapa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "abc123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. ¿Qué hace la función hash?
&lt;/h2&gt;

&lt;p&gt;¿Cómo hace el hashmap para ir directo al valor sin recorrer todo? Por debajo, un hashmap vive sobre un array, y los arrays solo entienden índices numéricos. Entonces necesitamos convertir la clave &lt;code&gt;"token"&lt;/code&gt; en un número. Eso pasa en dos pasos.&lt;/p&gt;

&lt;p&gt;Primero, la función hash toma la clave y devuelve un &lt;em&gt;hash code&lt;/em&gt;, que es un número (puede ser muy grande):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash("token")  → 8472361
hash("nombre") → 23847
hash("email")  → 91234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después, ese número se reduce al rango de buckets disponibles. Si el array tiene 8 buckets, lo más común es aplicar módulo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8472361 % 8 = 1
23847   % 8 = 7
91234   % 8 = 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ese resultado sí es el índice del bucket donde se guarda el par. Por eso los tamaños del array casi siempre son potencias de 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5swfh8banllqbobxaph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv5swfh8banllqbobxaph.png" alt="Diagrama: clave entra a la función hash, sale un hash code, y se reduce al índice del bucket con módulo" width="799" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para que una función hash sea útil, necesita tres propiedades:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Determinista.&lt;/strong&gt; La misma clave siempre produce el mismo número. Si &lt;code&gt;hash("token")&lt;/code&gt; hoy devuelve 1, mañana también devuelve 1. Sin esto, nunca encontrarías lo que guardaste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribución uniforme.&lt;/strong&gt; Los resultados deben repartirse de forma pareja entre todos los buckets disponibles. Si todos los valores caen en el mismo índice, el hashmap pierde su ventaja.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rápida de calcular.&lt;/strong&gt; La función hash se ejecuta en cada lectura y escritura. Si fuera lenta, arruinaría el O(1).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; la función hash de un hashmap no es lo mismo que el hashing criptográfico (SHA-256, bcrypt). El criptográfico está diseñado para ser difícil de revertir y resistente a ataques, mientras que el de un hashmap solo necesita ser rápido y distribuir bien.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. ¿Cómo funciona un hashmap por debajo?
&lt;/h2&gt;

&lt;p&gt;Ya sabemos que el hashmap vive sobre un array y que la función hash, junto con el módulo, convierte claves en índices. Veamos qué pasa en la práctica.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buckets
&lt;/h3&gt;

&lt;p&gt;Cada posición del array interno se llama bucket. El hashmap empieza con un tamaño fijo, generalmente una potencia de 2 (8, 16, 32...). Cuando guardas un par clave-valor, el índice resultante decide en qué bucket cae.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hwlq85utdexzwisqv9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hwlq85utdexzwisqv9i.png" alt="Buckets vacíos y luego con valores insertados" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Colisiones
&lt;/h3&gt;

&lt;p&gt;El espacio de claves posibles es enorme (cualquier string, número, objeto), pero el número de buckets es finito, así que tarde o temprano dos claves distintas van a caer en el mismo bucket. Puede pasar porque la función hash devolvió el mismo número, o porque devolvió números distintos que al aplicar el módulo cayeron en el mismo índice. Eso es una colisión, y manejarla bien es parte de cualquier implementación seria de hashmap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash("token") % 8 = 1
hash("rol")   % 8 = 1  ← colisión
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Chaining (encadenamiento)
&lt;/h3&gt;

&lt;p&gt;Una estrategia clásica es que cada bucket no guarde un solo par, sino una lista de todos los pares que cayeron ahí. Cuando hay colisión, el nuevo par se agrega a la lista del bucket.&lt;/p&gt;

&lt;p&gt;Para buscar, vas al bucket correcto y recorres la lista hasta encontrar la clave exacta.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fguk4qn14a8acsz2zfky7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fguk4qn14a8acsz2zfky7.png" alt="Diagrama de chaining: bucket con lista enlazada" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Open addressing (direccionamiento abierto)
&lt;/h3&gt;

&lt;p&gt;La otra estrategia es que si el bucket está ocupado, buscas el siguiente disponible. No hay listas, todos los pares viven directamente en el array.&lt;/p&gt;

&lt;p&gt;Hay varias formas de "buscar el siguiente":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linear probing:&lt;/strong&gt; revisa el siguiente bucket, luego el siguiente, y así.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quadratic probing:&lt;/strong&gt; salta de forma cuadrática (1, 4, 9, 16...) para evitar agrupar colisiones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double hashing:&lt;/strong&gt; aplica una segunda función hash para calcular el salto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figribh6ruevfqs6wxaqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figribh6ruevfqs6wxaqr.png" alt="Diagrama comparando chaining vs open addressing" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. ¿Cuándo crece un hashmap? Load factor y rehashing
&lt;/h2&gt;

&lt;p&gt;Hay un número que el hashmap monitorea constantemente: el load factor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load factor = elementos guardados / número de buckets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si tienes 8 buckets y 6 elementos guardados, tu load factor es 0.75. Cuando ese número supera cierto umbral (0.75 es el valor típico), el hashmap sabe que está demasiado lleno y que las colisiones van a empezar a afectar el rendimiento.&lt;/p&gt;

&lt;p&gt;Cuando eso pasa, hace rehashing: crea un array interno más grande (generalmente el doble) y redistribuye los pares existentes. Como &lt;code&gt;numBuckets&lt;/code&gt; cambió, el mismo hash code aplicado al módulo cae en un índice distinto, así que cada par puede terminar en otro bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. ¿Cuál es el Big O de un hashmap?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operación&lt;/th&gt;
&lt;th&gt;Caso promedio&lt;/th&gt;
&lt;th&gt;Peor caso&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set(k, v)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)*&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get(k)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delete(k)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has(k)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* Amortizado. Ocasionalmente O(n) cuando ocurre un rehashing.&lt;/p&gt;

&lt;p&gt;El peor caso O(n) existe, pero es teórico en la práctica. Ocurre cuando todas las claves caen en el mismo bucket, y como dentro de ese bucket toca recorrer todos los pares para encontrar el correcto, la búsqueda termina siendo lineal. Con una buena función hash y un load factor controlado, eso no pasa.&lt;/p&gt;

&lt;p&gt;Con implementaciones modernas estás casi siempre en O(1), y esa es la razón por la que los hashmaps son la primera herramienta que buscas cuando necesitas búsquedas rápidas. Buscar en un array es O(n) porque tienes que recorrerlo, buscar en un hashmap con la clave es O(1), y esa diferencia se vuelve enorme cuando tienes miles o millones de elementos.&lt;/p&gt;




&lt;p&gt;La próxima vez que uses &lt;code&gt;localStorage.getItem("token")&lt;/code&gt;, ya sabes qué está pasando por debajo.&lt;/p&gt;

&lt;p&gt;Si el artículo te sirvió, deja un ❤️ y nos vemos en el siguiente. 🙌🏻&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>programming</category>
      <category>newbie</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Cómo empezar a usar Node.js</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Mon, 01 Jun 2026 22:16:20 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/como-instalar-nodejs-498d</link>
      <guid>https://dev.to/fromchiapasdev/como-instalar-nodejs-498d</guid>
      <description>&lt;p&gt;Empezar con &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; es muy sencillo. No necesitas aprender un lenguaje de programación nuevo, utilizas JavaScript. Vamos a ver qué necesitas para comenzar con Node.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Si ya sé JavaScript puedo usar Node?
&lt;/h2&gt;

&lt;p&gt;Me acuerdo la primera vez que vi a alguien utilizando Node.js en el 2015 y se me hizo súper complicado entenderlo pero eso fue porque no sabía mucho de JavaScript. Lo mínimo que debes saber es esto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Callbacks&lt;/li&gt;
&lt;li&gt;Promesas (debes entender qué son y lo básico. No necesitas comprender todo lo que pasa por debajo)&lt;/li&gt;
&lt;li&gt;Async/Await&lt;/li&gt;
&lt;li&gt;Timers (setTimeout, setInterval)&lt;/li&gt;
&lt;li&gt;Fundamentos de JavaScript (arrays, strings, loops, entre otros)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como ves, necesitas únicamente saber JavaScript porque trabajar con Node.js no significa que vas a utilizar un lenguaje nuevo.&lt;/p&gt;

&lt;p&gt;Usar Node.js es como si escribieras JavaScript en la consola del DevTools de Chrome, la diferencia es que al usar Node.js nosotros podemos aprovechar la máquina donde va a ejecutarse nuestro JavaScript.&lt;/p&gt;

&lt;p&gt;Obtendremos acceso al sistema de archivos, a la red, a los procesos del sistema operativo, entre otras cosas.&lt;/p&gt;

&lt;p&gt;Por supuesto, Node.js tiene diferencias al momento de ejecutar el código que escribes pero eso se presta para un tema avanzado que podemos cubrir más adelante.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo instalar Node.js?
&lt;/h2&gt;

&lt;p&gt;Perfecto, espero que ya estés emocionad@ después de saber que no necesitas aprender un lenguaje nuevo y que puedes utilizar el JavaScript que ya aprendiste. Pero antes debemos instalar Node.js.&lt;/p&gt;

&lt;p&gt;¿Cómo que instalar? Así es, necesitamos instalar el ambiente de ejecución. Piensa en esto como si estuvieras descargando un navegador nuevo, la diferencia es que en vez de navegar en páginas, esta plataforma te da acceso a controlar la computadora con JavaScript.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un dato interesante es que Chrome utiliza algo llamado V8, es el sistema que hace posible que JavaScript se ejecute y Node.js también utiliza ese sistema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para instalar Node.js, dependiendo del sistema operativo que utilices necesitarás descargar el instalador o usar la línea de comandos.&lt;/p&gt;

&lt;p&gt;Vamos a cubrir la instalación usando la línea de comandos, si no te sientes cómod@ puedes usar el instalador pero yo te invito a que le pierdas el miedo a la terminal ya que te ayuda a ser más versátil.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instalar NVM
&lt;/h3&gt;

&lt;p&gt;Al querer instalar Node.js vas a darte cuenta que existen muchas versiones y quizás cuando ya tengas varios proyectos con Node.js vas a tener que usar diferentes versiones en cada uno de ellos. Y ese es un problema porque sería muy incómodo instalar la versión que necesitas y después desinstalarla para usar otra.&lt;/p&gt;

&lt;p&gt;Por eso se crearon los manejadores de versiones de Node.js. NVM es una herramienta que te permite cambiar entre versiones de Node.js sin tener que eliminar la que ya tenías y así poder trabajar en proyectos que requieran distintas versiones.&lt;/p&gt;

&lt;p&gt;Para instalar NVM es muy sencillo, únicamente necesitamos seguir los pasos del &lt;a href="https://github.com/nvm-sh/nvm#node-version-manager---" rel="noopener noreferrer"&gt;readme.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este es un ejemplo de lo que encuentras en el readme. Abres la terminal y ejecutas el comando, después necesitas reiniciar la terminal. Puedes abrir y cerrarla si se te hace más fácil.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Antes de copiar y pegar revisa cual es la ultima versión en el Readme. Si tiene menos de 1 día es preferible instalar la versión anterior a esa.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o-&lt;/span&gt; https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Instalar Node.js
&lt;/h3&gt;

&lt;p&gt;Ya que tienes NVM deberías de tener acceso a un comando en tu terminal llamado &lt;code&gt;nvm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lbcb0n62738i7xzzths.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lbcb0n62738i7xzzths.png" alt="Ejemplo de output comando NVM" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez que logres instalar NVM podemos instalar Node.js.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si te gustaría que haga un blog acerca de nvm déjalo en los comentarios.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Con el siguiente comando instalarás la versión LTS (Long Term Support), es decir, la versión activa de Node.js que está recibiendo actualizaciones de seguridad, features, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--lts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En mi terminal al ejecutar el comando puedo ver esto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdj1r7u03xyj8f86w0y0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdj1r7u03xyj8f86w0y0.png" alt="Ejemplo de output al instalar Node.js versión LTS" width="798" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ejecuta tu primer hola mundo
&lt;/h2&gt;

&lt;p&gt;¡Listo! Ya tenemos Node.js descargado, usamos NVM para manejar las versiones de Node.js. Entonces, si quisieras utilizar una versión distinta únicamente instalas la versión y utilizas el comando &lt;code&gt;nvm use &amp;lt;version&amp;gt;&lt;/code&gt; y nvm se encarga de cambiar de versión por ti.&lt;/p&gt;

&lt;p&gt;Ahora si ejecutas &lt;code&gt;node -v&lt;/code&gt; deberías ver la versión que estás ejecutando:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03q2zca64dv45ndjplb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03q2zca64dv45ndjplb8.png" alt="Ejemplo de salida al ejecutar node -v" width="274" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Después puedes ejecutar esto para ver el primer hola mundo usando Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'console.log("hello world")'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debería verse algo así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztgqtc8unjomkeyyruny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztgqtc8unjomkeyyruny.png" alt="Ejemplo de hola mundo usando Node.js desde la terminal" width="392" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cierre
&lt;/h2&gt;

&lt;p&gt;Listo, ya tenemos instalado Node.js y estás list@ para comenzar con tus proyectos. En los siguientes artículos seguiremos con más temas de Node.js para que te conviertas en expert@.&lt;/p&gt;

&lt;p&gt;Déjame en los comentarios qué fue lo que más te gustó o si tienes alguna pregunta escríbeme en instagram &lt;a class="mentioned-user" href="https://dev.to/fromchiapasdev"&gt;@fromchiapasdev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Stacks en entrevistas técnicas: 3 problemas resueltos paso a paso</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Wed, 27 May 2026 17:53:28 +0000</pubDate>
      <link>https://dev.to/aws/stacks-en-entrevistas-tecnicas-3-problemas-resueltos-paso-a-paso-o6e</link>
      <guid>https://dev.to/aws/stacks-en-entrevistas-tecnicas-3-problemas-resueltos-paso-a-paso-o6e</guid>
      <description>&lt;p&gt;Cuando empecé a resolver problemas de LeetCode cada uno se sentía como un mundo nuevo. Me costó un rato darme cuenta de que la mayoría se agrupan por estructura, y que si reconoces el patrón el problema se desarma solo. Hoy le toca a los stacks.&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://dev.to/aws/estructuras-de-datos-que-son-los-stacks-lifo-1d0n"&gt;artículo anterior vimos cómo funcionan los stacks por debajo&lt;/a&gt;. Hoy usamos esa base para resolver tres problemas clásicos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8lzp145i3v38gwf9ya6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8lzp145i3v38gwf9ya6.png" alt="Tres problemas distintos (balanced parentheses, reverse string, simplify path) convergiendo en un mismo stack que los resuelve" width="799" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lo que vas a encontrar:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tres problemas resueltos paso a paso: balanced parentheses, reverse string y simplify path&lt;/li&gt;
&lt;li&gt;Dónde aparecen los stacks fuera de las entrevistas&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Recordatorio rápido
&lt;/h2&gt;

&lt;p&gt;LIFO: el último que entra es el primero que sale. &lt;code&gt;push&lt;/code&gt; agrega al tope, &lt;code&gt;pop&lt;/code&gt; saca del tope. En JavaScript un array ya funciona como stack. Si necesitas el detalle completo, está en el &lt;a href="https://dev.to/aws/estructuras-de-datos-que-son-los-stacks-lifo-1d0n"&gt;artículo anterior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vamos a los problemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problema 1: Balanced Parentheses
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/valid-parentheses/description/" rel="noopener noreferrer"&gt;"Valid Parentheses" de LeetCode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Problema: dado un string &lt;code&gt;s&lt;/code&gt; con solo &lt;code&gt;()[]{}&lt;/code&gt;, determina si es válido. Cada apertura debe tener su cierre correspondiente y en el orden correcto.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  "()[]{}"   → true
Input:  "([)]"     → false
Input:  "{[]}"     → true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;"El último que abrió es el primero que debe cerrarse." Justo eso es lo que un stack hace bien.&lt;/p&gt;

&lt;p&gt;Recorremos el string. Cada apertura va al stack. Cada cierre debe coincidir con el tope. Si al final el stack queda vacío, todo cerró bien.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fse53h0183nqf2fo22ius.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fse53h0183nqf2fo22ius.png" alt="Paso a paso del stack validando balanced parentheses" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validParentheses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo importante:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;pairs&lt;/code&gt; mapea cada cierre con su apertura.&lt;/li&gt;
&lt;li&gt;Aperturas van al stack. Cierres hacen &lt;code&gt;pop&lt;/code&gt; y validan.&lt;/li&gt;
&lt;li&gt;Si el stack está vacío al hacer &lt;code&gt;pop&lt;/code&gt;, devuelve &lt;code&gt;undefined&lt;/code&gt; y la comparación falla. Cómodo, así no necesitamos un chequeo extra.&lt;/li&gt;
&lt;li&gt;Al final, el stack debe estar vacío.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Complejidad: O(n) tiempo y O(n) espacio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Problema 2: Reverse String (easy)
&lt;/h2&gt;

&lt;p&gt;Adaptación de &lt;a href="https://leetcode.com/problems/reverse-string/description/" rel="noopener noreferrer"&gt;"Reverse String" de LeetCode&lt;/a&gt;. Vamos a invertir una palabra usando stack.&lt;/p&gt;

&lt;p&gt;Problema: dado un string &lt;code&gt;s&lt;/code&gt;, devuelve el string invertido.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  "stack"   → "kcats"
Input:  "hello"   → "olleh"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;"Invertir" es la pista. Metes los elementos en orden y los sacas en orden inverso. Eso es exactamente lo que hace un stack.&lt;/p&gt;

&lt;p&gt;En la vida real usarías &lt;code&gt;s.split("").reverse().join("")&lt;/code&gt; y listo. Aquí lo hacemos con stack para ver el patrón en acción.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vk6wkdys44zopqapji8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vk6wkdys44zopqapji8.png" alt="Paso a paso del stack invirtiendo la palabra stack" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;reverseString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// crea un stack con los caracteres&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;reversed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reversed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Metemos todos los caracteres al stack y los vamos sacando uno por uno. Como &lt;code&gt;pop&lt;/code&gt; devuelve el último que entró, los caracteres salen al revés.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Complejidad: O(n) tiempo y O(n) espacio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Problema 3: Simplify Path (medium)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/simplify-path/description/" rel="noopener noreferrer"&gt;"Simplify Path" de LeetCode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Problema: dada una ruta absoluta de Unix, conviértela a su forma canónica.&lt;/p&gt;

&lt;p&gt;Reglas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; es el directorio actual.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;..&lt;/code&gt; sube un nivel.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;//&lt;/code&gt; se trata como &lt;code&gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;El resultado no termina en &lt;code&gt;/&lt;/code&gt;, salvo la raíz.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  "/home//foo/"       → "/home/foo"
Input:  "/../"              → "/"
Input:  "/a/./b/../../c/"   → "/c"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;¿Qué hace &lt;code&gt;..&lt;/code&gt;? Nos regresa al directorio anterior. Ahí está la señal, necesitamos recordar por dónde pasamos y poder retroceder.&lt;/p&gt;

&lt;p&gt;Partimos la ruta por &lt;code&gt;/&lt;/code&gt; y recorremos cada componente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;""&lt;/code&gt; o &lt;code&gt;"."&lt;/code&gt;, ignora.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;".."&lt;/code&gt;, saca el tope del stack.&lt;/li&gt;
&lt;li&gt;Cualquier otra cosa es un directorio y va al stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Al final, el stack contiene los directorios de la ruta simplificada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flc69jgaauw38rep36yld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flc69jgaauw38rep36yld.png" alt="Paso a paso del stack simplificando una ruta de Unix" width="799" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;simplifyPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;part&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;part&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: en JavaScript, &lt;code&gt;pop&lt;/code&gt; sobre un stack vacío no rompe nada, solo devuelve &lt;code&gt;undefined&lt;/code&gt;. Así que si la ruta intenta subir más allá de la raíz, no hace falta validación extra.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Complejidad: O(n) tiempo y O(n) espacio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  El patrón detrás de los tres
&lt;/h2&gt;

&lt;p&gt;Si los lees seguidos vas a notar lo mismo. Los tres resuelven el mismo problema de fondo, poder regresar a algo anterior.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Balanced parentheses: recordar la última apertura para validar el cierre.&lt;/li&gt;
&lt;li&gt;Reverse string: regresar al orden opuesto.&lt;/li&gt;
&lt;li&gt;Simplify path: &lt;code&gt;..&lt;/code&gt; regresa un nivel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ese es el superpoder del stack. Cuando un problema te pide recordar lo último, deshacer algo o procesar de atrás hacia adelante, casi siempre la respuesta es stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stacks más allá de las entrevistas
&lt;/h2&gt;

&lt;p&gt;Los stacks no son trivia de entrevistas. El patrón de "regresar" aparece por todos lados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El botón de regresar del navegador es un stack.&lt;/li&gt;
&lt;li&gt;El undo/redo de tu editor también.&lt;/li&gt;
&lt;li&gt;Los call stacks de los lenguajes (por eso existen los stack overflow errors).&lt;/li&gt;
&lt;li&gt;Pipelines de datos que necesitan mantener contexto de lo último visto.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Para seguir practicando
&lt;/h2&gt;

&lt;p&gt;Problemas de LeetCode ordenados por dificultad:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://leetcode.com/problems/min-stack/description/" rel="noopener noreferrer"&gt;Min Stack&lt;/a&gt;, easy.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://leetcode.com/problems/baseball-game/description/" rel="noopener noreferrer"&gt;Baseball Game&lt;/a&gt;, easy.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://leetcode.com/problems/evaluate-reverse-polish-notation/description/" rel="noopener noreferrer"&gt;Evaluate Reverse Polish Notation&lt;/a&gt;, medium.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://leetcode.com/problems/daily-temperatures/description/" rel="noopener noreferrer"&gt;Daily Temperatures&lt;/a&gt;, medium. Es la intro al patrón de monotonic stack.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;¿Cuál te costó más? Déjamelo en los comentarios. A mí Simplify Path me hizo dar más vueltas para resolverlo.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Cómo destacar como JR DEV en tu equipo</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 26 May 2026 19:33:38 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/como-destacar-como-jr-dev-en-tu-equipo-5kg</link>
      <guid>https://dev.to/fromchiapasdev/como-destacar-como-jr-dev-en-tu-equipo-5kg</guid>
      <description>&lt;p&gt;Cuando entré a mi primer trabajo de desarrollador venía con una idea muy clara de lo que iba a hacer. Patrones de diseño, arquitectura, UML, escribir código limpio desde cero. Llegué con la mochila llena de cosas que aprendí en la escuela y en cursos.&lt;/p&gt;

&lt;p&gt;A los pocos días me di cuenta de que la realidad era otra.&lt;/p&gt;

&lt;p&gt;No estoy diciendo que lo que aprendí no sirviera. Sirve, y mucho. Pero el trabajo del día a día no se parecía a los proyectos personales ni a los ejercicios de clase. Era otra cosa.&lt;/p&gt;

&lt;p&gt;Lo que te comparto aquí está basado en mi experiencia. Son cosas que viví, errores que cometí, y aprendizajes que fui agarrando con el tiempo. Si vas entrando a tu primer trabajo o llevas pocos meses, espero que te sirva para no chocar con los mismos muros que yo y para crecer más rápido de lo que yo lo hice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Resumen rápido: aprende a leer código ajeno, propón cambios con argumentos, escribe pruebas útiles, documenta lo que aprendes, pregunta antes de programar, entiende el negocio, pide ayuda rápido, habla en los meetings, lleva registro de lo que haces y únete a comunidades. Suena obvio, pero nadie te lo dice antes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Aprende a leer código ajeno
&lt;/h2&gt;

&lt;p&gt;Cuando entré a mi primer trabajo pensé que iba a diseñar sistemas desde cero. Arquitectura hexagonal, Clean Code, patrones de diseño. Pasé semanas leyendo código que escribió alguien que ya ni trabaja en la empresa, intentando entender por qué tal función hacía lo que hacía.&lt;/p&gt;

&lt;p&gt;Al principio me frustré. Después entendí que eso era el trabajo.&lt;/p&gt;

&lt;p&gt;La mayor parte del tiempo vas a mejorar lo que otras personas ya hicieron. Agregar un pedacito, arreglar lo que está roto sin romper lo que sí funciona. Y mientras más rápido aprendas a leer código ajeno, más rápido vas a entender el sistema completo y más valor vas a aportar.&lt;/p&gt;

&lt;p&gt;Esa habilidad, leer código, es lo que te diferencia en los primeros meses. No el framework que conoces ni los patrones que estudiaste.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; cuando entres a un proyecto nuevo, dale dos o tres días solo a leer. Sin tocar nada. Toma notas, dibuja diagramas a mano, anota dudas. Vas a avanzar más rápido cuando empieces a programar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Aprende a proponer cambios con argumentos, no con opiniones
&lt;/h2&gt;

&lt;p&gt;Cuando llegué a una empresa me encontré con proyectos legacy enormes. Monolitos de los que dependían muchas otras cosas y muchos otros equipos. Yo quería proponer migrar a microservicios, actualizar el framework, modernizar todo.&lt;/p&gt;

&lt;p&gt;Nadie me hizo caso. Y tenían razón.&lt;/p&gt;

&lt;p&gt;Mover un sistema así puede tomar meses. A veces años. Y mientras tanto el negocio sigue corriendo, los clientes siguen pagando. Nadie va a detener eso para esperar a que termines de migrar.&lt;/p&gt;

&lt;p&gt;Lo que aprendí es que la diferencia entre un JR que propone cosas y uno que las ve implementadas es cómo las presenta. Una opinión es "deberíamos actualizar esto". Un argumento es "esta versión tiene una vulnerabilidad de seguridad conocida, migrar nos tomaría dos sprints, y si no lo hacemos corremos este riesgo".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; antes de proponer una actualización o migración, prepara tres cosas: el problema concreto que resuelve, el costo estimado en tiempo, y el riesgo de no hacerlo. Con eso tienes una conversación real con tu equipo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Escribe pruebas que de verdad prueben algo
&lt;/h2&gt;

&lt;p&gt;Yo venía con la idea de que las pruebas unitarias eran sagradas. Llegué pensando que iba a encontrar suites de tests bien hechas, con cobertura útil, validando edge cases.&lt;/p&gt;

&lt;p&gt;Lo que me encontré fue otra cosa. Pruebas que validan cosas obvias. Pruebas con mocks tan cargados que terminan probando el mock y no el código. Pruebas escritas únicamente para llegar al 80% de cobertura que pide el pipeline. Y nadie las entiende porque las escribió alguien que ya se fue.&lt;/p&gt;

&lt;p&gt;Aquí está la oportunidad. Cuando el equipo tiene esa cultura, tú puedes destacar haciendo lo contrario. Escribe pruebas que cubran los casos donde el código se puede romper. Que un compañero pueda leerlas y entender qué están validando.&lt;/p&gt;

&lt;p&gt;Va a tomar más tiempo que copiar el patrón malo del repo. Pero te va a salvar de bugs en producción, y poco a poco la gente del equipo se da cuenta y empieza a hacer lo mismo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; la próxima vez que escribas una prueba, hazte esta pregunta antes de terminar: "¿si alguien rompe esta función, mi prueba lo detecta?" Si la respuesta es no, reescríbela.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Documenta lo que aprendes, aunque nadie te lo pida
&lt;/h2&gt;

&lt;p&gt;He trabajado en proyectos donde el README dice cosas que dejaron de ser ciertas hace dos años. En otros, el README es solo el comando de instalación. Y en algunos, no hay nada.&lt;/p&gt;

&lt;p&gt;Eso es una oportunidad.&lt;/p&gt;

&lt;p&gt;Cuando eres el nuevo y te toca entender el sistema desde cero, cada cosa que descubres tiene valor. Por qué tal servicio hace lo que hace, cómo se conecta con el otro, qué pasa si falla. Escríbelo. En una wiki interna, Confluence, Notion, donde sea, pero que todo el equipo pueda verlo.&lt;/p&gt;

&lt;p&gt;Esto te sirve a ti porque dentro de seis meses no te vas a acordar. Le sirve a la persona nueva que va a entrar. Y cuando la gente ve que tú escribes documentación, algunos empiezan a hacer lo mismo.&lt;/p&gt;

&lt;p&gt;No te desanimes si al principio nadie la lee. La vas a usar tú primero, y eso ya justifica el esfuerzo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; esta semana, cuando resuelvas algo que no estaba documentado, escríbelo. Una sola entrada. Dónde está, qué hace, por qué funciona así. Cinco minutos. Eso es todo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Pregunta antes de programar
&lt;/h2&gt;

&lt;p&gt;A mí me pasó muchas veces que recibí un ticket con pasos detallados, lo hice al pie de la letra, y al final el usuario decía "no, eso no era lo que necesitaba". Es frustrante para los dos.&lt;/p&gt;

&lt;p&gt;El problema no era el código. Era que nunca pregunté para qué servía lo que estaba construyendo.&lt;/p&gt;

&lt;p&gt;Los tickets ambiguos son normales. "Agregar botón de exportar" sin decir qué exporta, en qué formato, quién lo va a usar. Una lista de pasos sin contexto del problema que están tratando de resolver. Eso va a pasar siempre. La diferencia está en si arrancas a programar de inmediato o si primero entiendes qué estás resolviendo.&lt;/p&gt;

&lt;p&gt;Cuando un ticket no tiene contexto suficiente, pregunta. ¿Para qué se va a usar esto? ¿Qué problema resuelve? ¿Qué pasa si no lo hacemos? Muchas veces salen detalles que el ticket no decía, y a veces descubres que la solución que pedían no era la que necesitaban.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; la próxima vez que recibas un ticket, antes de abrir el editor, escribe en dos oraciones qué problema resuelve y para quién. Si no puedes, el ticket está incompleto y hay que preguntar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Entiende el negocio detrás del software
&lt;/h2&gt;

&lt;p&gt;Esto está conectado con el punto anterior, pero va más allá.&lt;/p&gt;

&lt;p&gt;Conocer el negocio te hace mejor desarrollador. Suena raro, pero es cierto. Cuando entiendes para qué se va a usar lo que estás construyendo, qué clientes lo van a tocar, cuánto vale para la empresa, tomas mejores decisiones técnicas.&lt;/p&gt;

&lt;p&gt;Te pongo el caso del ticket. Si el ticket sí tiene una definición completa, igual vale la pena cuestionar. ¿Esto es bueno para el usuario final? ¿Hay otra parte del sistema que se va a ver afectada con este cambio? ¿Existe una solución más simple que la que están proponiendo?&lt;/p&gt;

&lt;p&gt;Cuando haces estas preguntas dejas de ser solo el que ejecuta tickets y empiezas a aportar al producto. Eso es lo que te diferencia. Tu manager se va a dar cuenta. Tu equipo también.&lt;/p&gt;

&lt;p&gt;Y para entender el negocio no tienes que meterte en cursos de business ni leer libros de estrategia. Solo platica con la gente de producto, con soporte, con ventas. Pregúntales qué problemas tienen los clientes. Mete la nariz en las métricas del producto si tienes acceso. En poco tiempo vas a ver resultados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; agenda una llamada de 30 minutos con alguien de producto o soporte. Solo para escuchar. Pregúntales qué es lo que más les reportan los clientes. Esa conversación te va a cambiar cómo ves tu trabajo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Pide ayuda rápido
&lt;/h2&gt;

&lt;p&gt;Este es el punto que a mí me hubiera gustado escuchar más temprano.&lt;/p&gt;

&lt;p&gt;Yo soy bastante necio con los problemas. Me encanta resolverlos por mi cuenta, sentir el placer de cerrar las 45 pestañas de Stack Overflow después de horas peleando con un bug. Pero esto a veces juega en contra.&lt;/p&gt;

&lt;p&gt;Pasa así. Te trabas en algo, te das cuenta de que no avanzas, pero te sientes mal pidiendo ayuda. Entonces sigues intentando. Pasan dos horas. Cuatro. Un día. Y al final pides ayuda y resulta que alguien del equipo lo había visto antes y te lo resolvía en quince minutos.&lt;/p&gt;

&lt;p&gt;Lo que hago ahora es ponerme un timebox. Una o dos horas máximo intentándolo solo. Si no resuelvo, pido ayuda. Eso le ahorra tiempo al equipo y a mí.&lt;/p&gt;

&lt;p&gt;Y cuando pidas ayuda, hazlo bien. No llegues con "no me funciona". Llega con "estoy intentando hacer X, probé Y y Z, esperaba que pasara A pero pasa B, aquí está el error". Eso le ahorra tiempo a quien te ayuda y aprendes a estructurar problemas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; pon un timer de una hora la próxima vez que te trabes. Si suena y no resolviste, para y pide ayuda. Sin culpa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  8. No tengas miedo de hablar en los meetings
&lt;/h2&gt;

&lt;p&gt;Cuando entré a trabajar me quedaba callado en las llamadas. Esperaba a que alguien con más experiencia hablara y yo solo asentía. Tenía miedo de equivocarme, de decir algo tonto, de que la gente pensara que no sabía.&lt;/p&gt;

&lt;p&gt;Después de un tiempo le pregunté al senior del equipo qué me hacía falta para crecer. Una persona con la misma experiencia que yo había sido promovida y yo no. Me dijo: "casi no hablas en las llamadas".&lt;/p&gt;

&lt;p&gt;Me explicó que no se trataba de hablar por hablar. Era dar mi opinión, cuestionar cuando no estaba de acuerdo, proponer ideas. No solo aceptar todo lo que decían los demás.&lt;/p&gt;

&lt;p&gt;Esto fue duro de aceptar. Pero tenía razón.&lt;/p&gt;

&lt;p&gt;Empecé a forzarme a hablar. Aunque tuviera miedo. Aunque pensara que mi idea no era tan buena. Y la verdad es que muchas veces me equivoqué. Pero también muchas veces aporté algo útil que nadie había considerado.&lt;/p&gt;

&lt;p&gt;Hoy en día sigo sintiendo nervios antes de hablar en juntas grandes. Sigue ahí ese miedo. Pero también recuerdo que cada vez que aporto, construyo confianza con mi equipo. Y eso es lo que hace que la gente te tome en serio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; en tu próxima junta, di una cosa. Una opinión, una pregunta, una duda. Solo una. No tienes que resolver todo, solo participar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  9. Lleva un registro de tus contribuciones
&lt;/h2&gt;

&lt;p&gt;Este punto no me lo enseñaron nunca y es probablemente el más importante para destacar.&lt;/p&gt;

&lt;p&gt;Tu equipo y tu manager necesitan saber qué haces. Suena obvio, pero no lo es. Por más que pensemos que los demás se acuerdan de lo que hicimos, no es así. La gente tiene su propio trabajo, sus propios problemas, sus propias prioridades.&lt;/p&gt;

&lt;p&gt;Lleva un documento, en Word, Notion, Notes, donde sea, y anota tus contribuciones cada semana. No tiene que ser elegante, solo tiene que existir.&lt;/p&gt;

&lt;p&gt;La forma en que lo escribas importa. Si solo anotas tareas, te sirve poco. Si lo enfocas en impacto, te sirve mucho.&lt;/p&gt;

&lt;p&gt;Compara estos dos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Llamada con Juan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Apoyé a Juan a resolver un error en el sistema de pagos.
  Esto desbloqueó el proceso de cobros que llevaba 2 semanas
  fallando para 200 clientes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las dos describen la misma reunión. Pero la segunda te ayuda en performance reviews, en conversaciones con tu manager, en negociaciones de aumento. Cuando llega el momento de demostrar tu valor, este documento es oro.&lt;/p&gt;

&lt;p&gt;Cuando te llamen para una entrevista futura, vas a tener un registro real de lo que hiciste. Sin tener que pensar "¿qué hice los últimos dos años?".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; abre un documento ahora y escribe tres cosas que hiciste esta semana, enfocadas en impacto. Si no recuerdas tres, escribe una. El hábito empieza con una entrada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  10. Únete a comunidades
&lt;/h2&gt;

&lt;p&gt;Todo lo anterior pasa dentro de tu equipo. Pero crecer rápido también pasa por la gente que conoces fuera de él.&lt;/p&gt;

&lt;p&gt;Las comunidades son ese espacio donde aprendes cosas que en tu empresa nadie usa, ves cómo otras personas resuelven los mismos problemas que tú, y conoces gente que después se convierte en tu red. Esa red te abre puertas que un CV nunca te va a abrir. Recomendaciones, oportunidades de trabajo, mentores, amigos que la pasaron mal con el mismo bug que tú.&lt;/p&gt;

&lt;p&gt;¿Pero dónde encuentro comunidades? Una opción es &lt;a href="https://builder.aws.com/community?trk=02b062ab-d194-401f-85b7-db6aae204076&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS Builder Center&lt;/a&gt;. Ahí encuentras grupos de usuarios por ciudad, student builder groups que son comunidades lideradas por estudiantes, y eventos donde puedes ir a aprender o presentar.&lt;/p&gt;

&lt;p&gt;No tienes que llegar a hablar en un meetup el primer día. Empieza yendo a escuchar. Después haz una pregunta. Después platica con alguien al final del evento. Y un día te das cuenta de que ya conoces a varias personas y aprendiste cosas que ni en el trabajo ni en cursos ibas a aprender.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Acción:&lt;/strong&gt; entra a &lt;a href="https://builder.aws.com/community?trk=02b062ab-d194-401f-85b7-db6aae204076&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS Builder Center&lt;/a&gt;, busca un grupo en tu ciudad o un student builder group, y anótate al próximo evento. Solo ir ya cuenta.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cierre
&lt;/h2&gt;

&lt;p&gt;Si tuviera que resumir todo en una idea, sería esta. Ser un buen JR no es saber más que los demás. Es leer código con paciencia, hablar con la gente, escribir lo que aprendes y llevar cuenta de lo que haces.&lt;/p&gt;

&lt;p&gt;Lo demás llega con el tiempo.&lt;/p&gt;

&lt;p&gt;Cada punto de este artículo tiene una acción concreta. No tienes que hacer las diez esta semana. Elige una, aplícala, y cuando ya sea hábito agrega otra. Si me preguntas por dónde empezar, empieza por el registro de contribuciones. Es el de menor fricción y el que más rendimiento te va a dar a largo plazo.&lt;/p&gt;

&lt;p&gt;¿Cuál de estos puntos te resuena más? ¿O hay algo que tú hayas aprendido en tu primer trabajo que no está aquí? Déjamelo en los comentarios, me interesa leerlo.&lt;/p&gt;

&lt;p&gt;Y si quieres seguir la conversación, me encuentras en Instagram como &lt;a href="https://www.instagram.com/fromchiapasdev" rel="noopener noreferrer"&gt;@fromchiapasdev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>career</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Why you keep attacking npm?</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 12 May 2026 22:39:43 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/why-you-keep-attacking-npm-4a53</link>
      <guid>https://dev.to/fromchiapasdev/why-you-keep-attacking-npm-4a53</guid>
      <description>&lt;p&gt;Honestly, it's exhausting to wake up and find out there's yet another attack on the npm ecosystem.&lt;/p&gt;

&lt;p&gt;Socket shared &lt;a href="https://x.com/SocketSecurity/status/2054048025081737446" rel="noopener noreferrer"&gt;via social media&lt;/a&gt; that they identified compromised packages — some of them were TanStack.&lt;/p&gt;

&lt;p&gt;Why are attackers so obsessed with npm? Seriously, can you stop already?&lt;/p&gt;

&lt;p&gt;If you still use npm and haven't disabled post-scripts, you're in serious danger.&lt;/p&gt;

&lt;p&gt;Go and disable that right now.&lt;/p&gt;

&lt;p&gt;Start using pnpm. Version 11 disables this functionality by default. Of course, some packages still need post-scripts, and in those cases you should manually review and authorize them.&lt;/p&gt;

&lt;p&gt;Also, there are tools you can use before installing a package: Socket's &lt;a href="https://docs.socket.dev/docs/socket-firewall-free" rel="noopener noreferrer"&gt;sfw&lt;/a&gt; and &lt;a href="https://github.com/lirantal/npq" rel="noopener noreferrer"&gt;npq&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope this helps.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>npm</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Can you stop attacking #npm packages? I'm scared of installing packages. Now it's time to switch 100% to PNPM...</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 12 May 2026 22:21:32 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/can-you-stop-attacking-npm-packages-im-scared-of-installing-packages-now-its-time-to-switch-1aa4</link>
      <guid>https://dev.to/fromchiapasdev/can-you-stop-attacking-npm-packages-im-scared-of-installing-packages-now-its-time-to-switch-1aa4</guid>
      <description></description>
      <category>node</category>
      <category>discuss</category>
      <category>javascript</category>
    </item>
    <item>
      <title>¿Qué son los Stacks (LIFO)?</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Fri, 08 May 2026 21:22:09 +0000</pubDate>
      <link>https://dev.to/aws/estructuras-de-datos-que-son-los-stacks-lifo-1d0n</link>
      <guid>https://dev.to/aws/estructuras-de-datos-que-son-los-stacks-lifo-1d0n</guid>
      <description>&lt;p&gt;¿Alguna vez te has preguntado qué pasa cuando presionas el botón "atrás" en tu navegador? ¿O cómo &lt;code&gt;Ctrl + Z&lt;/code&gt; sabe exactamente qué acción deshacer? Detrás de esas funciones hay una estructura de datos que llevas años usando sin darte cuenta: el stack.&lt;/p&gt;

&lt;p&gt;En los artículos anteriores vimos los &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;arrays&lt;/a&gt; y los &lt;a href="https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-2lgn"&gt;strings&lt;/a&gt;. Hoy toca hablar de la siguiente pieza: los stacks. Si los arrays son el almacén general, el stack es una pila de platos. Ya lo vas a ver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo44qgfbopv1qjuo5c1pe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo44qgfbopv1qjuo5c1pe.png" alt="Todo esto que ya usas es un stack: botón atrás, Ctrl+Z y stack traces" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lo que encontrarás en este artículo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué es un stack y qué significa LIFO&lt;/li&gt;
&lt;li&gt;Las operaciones básicas: push, pop, peek, size, isEmpty&lt;/li&gt;
&lt;li&gt;Cómo implementar tu propio stack en JavaScript&lt;/li&gt;
&lt;li&gt;La complejidad Big O de cada operación&lt;/li&gt;
&lt;li&gt;Dónde se usan los stacks en la vida real&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ¿Qué es un stack?
&lt;/h2&gt;

&lt;p&gt;Un stack (o pila) es una estructura de datos que sigue el principio &lt;strong&gt;LIFO: Last In, First Out&lt;/strong&gt;. En español: el último que entra es el primero que sale.&lt;/p&gt;

&lt;p&gt;Imagina una pila de libros sobre tu escritorio. Vas apilándolos uno sobre otro. Cuando quieres leer uno, ¿por cuál empiezas? Por el de arriba, no por el de abajo. El último libro que pusiste es el primero que vas a tomar.&lt;/p&gt;

&lt;p&gt;Esa es la esencia de un stack. No puedes sacar un elemento del medio o del fondo. Solo trabajas con el que está hasta arriba.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcku5pmn7qj6isjnc8amj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcku5pmn7qj6isjnc8amj.png" alt="LIFO: Last In, First Out" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero aquí viene el detalle interesante: aunque suene restrictivo, esta limitación es justo lo que hace al stack útil. Cuando solo te importa el último elemento agregado, un stack es la herramienta perfecta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operaciones básicas de un stack
&lt;/h2&gt;

&lt;p&gt;Un stack tiene cinco operaciones fundamentales. Estas son las que aparecen en el ADT (Abstract Data Type) de un stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;push(item)&lt;/code&gt;: agrega un elemento a la parte superior&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pop()&lt;/code&gt;: elimina el elemento de arriba y lo devuelve&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;peek()&lt;/code&gt;: mira el elemento de arriba sin eliminarlo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;size()&lt;/code&gt;: devuelve cuántos elementos hay en el stack&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isEmpty()&lt;/code&gt;: dice si el stack está vacío o no&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Las dos estrellas son &lt;code&gt;push&lt;/code&gt; y &lt;code&gt;pop&lt;/code&gt;. Con ellas agregas y quitas elementos, siempre desde la misma puerta: la de arriba.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9gqqyr24femkwdeopc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9gqqyr24femkwdeopc6.png" alt="push y pop paso a paso" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fíjate en cómo &lt;code&gt;pop()&lt;/code&gt; siempre saca el último que entró. En el paso 3 agregamos 🐱, y en el paso 4 &lt;code&gt;pop()&lt;/code&gt; nos devuelve 🐱. Si hubiéramos hecho &lt;code&gt;pop()&lt;/code&gt; otra vez, nos devolvería 🐶.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cómo implementar un stack en JavaScript
&lt;/h2&gt;

&lt;p&gt;Dato curioso antes de empezar: los arrays en JavaScript ya se comportan como un stack. Si haces &lt;code&gt;miArray.push(x)&lt;/code&gt; y &lt;code&gt;miArray.pop()&lt;/code&gt;, estás trabajando como si fuera un stack..&lt;/p&gt;

&lt;p&gt;Pero un array te deja hacer cosas que un stack no debería permitir: acceder por cualquier índice, &lt;code&gt;unshift&lt;/code&gt;, &lt;code&gt;splice&lt;/code&gt;, lo que quieras. Y esa libertad de más es justo lo que queremos esconder.&lt;/p&gt;

&lt;p&gt;Así que vamos a implementarlo desde cero. Sin usar &lt;code&gt;.push()&lt;/code&gt; ni &lt;code&gt;.pop()&lt;/code&gt; del array. Solo lo vamos a usar como almacenamiento indexado y el control lo lleva nosotros. Así se ve qué pasa por debajo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// posición donde iría el próximo elemento&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;El stack está vacío&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// recortamos el array&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;El stack está vacío&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Probemos cómo se usa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;miStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐶&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐱&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "👻" (solo mira, no elimina)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "👻" (lo elimina y devuelve)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Así se ve el stack en cada paso:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifm64jmuvcn9tj2aqnzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifm64jmuvcn9tj2aqnzt.png" alt="Paso a paso de push, peek y pop sobre miStack" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Puedes probar este código en &lt;a href="https://runjs.app/play" rel="noopener noreferrer"&gt;RunJS&lt;/a&gt; o verlo paso a paso en &lt;a href="https://pythontutor.com/visualize.html#mode=edit" rel="noopener noreferrer"&gt;PythonTutor&lt;/a&gt;, que también soporta JavaScript.&lt;/p&gt;

&lt;p&gt;Vamos a desarmar lo que está pasando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;count&lt;/code&gt; lleva la cuenta de cuántos elementos hay. También indica la siguiente posición libre del array. Recuerda que los arrays empiezan en el índice 0, así que cuando el stack está vacío &lt;code&gt;count&lt;/code&gt; vale 0 y ese es justo el lugar donde va a caer el primer elemento.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;push()&lt;/code&gt; coloca el nuevo elemento en la posición &lt;code&gt;count&lt;/code&gt; y luego incrementa el contador.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pop()&lt;/code&gt; hace lo contrario: decrementa &lt;code&gt;count&lt;/code&gt; primero (ahora apunta al último elemento), lee ese valor y recorta el array.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;peek()&lt;/code&gt; lee la posición &lt;code&gt;count - 1&lt;/code&gt; (el último elemento) sin mover nada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ejemplo, si hacemos &lt;code&gt;push("🐶")&lt;/code&gt;, &lt;code&gt;push("🐱")&lt;/code&gt;, &lt;code&gt;push("👻")&lt;/code&gt;, el array queda así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxl2g84clcfs1afg5taz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxl2g84clcfs1afg5taz6.png" alt="Estado interno del stack" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando hacemos &lt;code&gt;pop()&lt;/code&gt;, el contador baja de 3 a 2 y leemos &lt;code&gt;items[2]&lt;/code&gt; que es 👻. Luego hacemos &lt;code&gt;this.items.length = 2&lt;/code&gt; para recortar el array, y listo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Un truco de los arrays en JavaScript
&lt;/h3&gt;

&lt;p&gt;Fíjate en esta línea: &lt;code&gt;this.items.length = this.count&lt;/code&gt;. Podría parecer que solo estamos "cambiando un número", pero en realidad estamos &lt;strong&gt;modificando el array&lt;/strong&gt;. En JavaScript, asignarle un valor menor a &lt;code&gt;.length&lt;/code&gt; recorta el array y elimina los elementos que sobran.&lt;/p&gt;

&lt;p&gt;Míralo por fuera de la clase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 5&lt;/span&gt;

&lt;span class="c1"&gt;// Definir la longitud&lt;/span&gt;
&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [1, 2, 3]&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// undefined (los elementos extra se eliminan)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este es un detalle que muchos desarrolladores desconocen y te abre posibilidades interesantes. En nuestra clase lo usamos para asegurarnos de que el array y el contador &lt;code&gt;count&lt;/code&gt; siempre estén sincronizados.&lt;/p&gt;

&lt;p&gt;Si te fijas, no usamos los métodos &lt;code&gt;push&lt;/code&gt; y &lt;code&gt;pop&lt;/code&gt; del array nativo de JavaScript. Solo lo usamos como almacenamiento indexado. Todo el control lo lleva nuestra variable &lt;code&gt;count&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complejidad Big O de las operaciones
&lt;/h2&gt;

&lt;p&gt;Ya vimos qué hace cada operación. Ahora, ¿cuánto cuestan? Aquí es donde entra &lt;a href="https://www.freecodecamp.org/espanol/news/explicacion-de-la-notacion-big-o-con-ejemplo/" rel="noopener noreferrer"&gt;Big O&lt;/a&gt;, la notación que nos dice cómo crece el tiempo de una operación conforme crece el stack.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operación&lt;/th&gt;
&lt;th&gt;Complejidad en tiempo&lt;/th&gt;
&lt;th&gt;Complejidad en espacio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;push()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)*&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;peek()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;size()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isEmpty()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* Amortizado. Ocasionalmente O(n) cuando el array dinámico necesita crecer por debajo.&lt;/p&gt;

&lt;p&gt;Todas las operaciones de un stack son O(1). ¿Por qué? Porque siempre trabajamos con un solo elemento: el de arriba. No importa si el stack tiene 10 o 10 millones de elementos, &lt;code&gt;push&lt;/code&gt; y &lt;code&gt;pop&lt;/code&gt; tardan lo mismo.&lt;/p&gt;

&lt;p&gt;Compara esto con un array, donde insertar al inicio es O(n) porque hay que mover todos los elementos. En un stack no tenemos ese problema porque solo tocamos la punta.&lt;/p&gt;

&lt;p&gt;Esta es la razón principal por la que los stacks se usan tanto: son rápidos y predecibles. Si tu problema solo necesita trabajar con el último elemento agregado, un stack te da esa operación en tiempo constante.&lt;/p&gt;

&lt;p&gt;Eso sí, rápido no quiere decir infinito. Un stack vive en memoria, así que si crece demasiado va a depender por completo de los recursos del dispositivo donde corra. En celulares, tablets y computadoras con poca RAM esto importa más de lo que crees: un stack que crece sin control puede tronar la app. Los lenguajes hasta tienen un límite específico para el call stack, y si lo rebasas te topas con el famoso &lt;em&gt;stack overflow&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Dónde se usan los stacks en la vida real?
&lt;/h2&gt;

&lt;p&gt;Antes de ver ejemplos, quédate con esto:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Regla de oro:&lt;/strong&gt; cuando lo único que te importa es el último elemento, un stack es la respuesta.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Todo lo que viene a continuación es una variante del mismo patrón. Una vez que lo ves, empiezas a reconocer stacks en todos lados.&lt;/p&gt;

&lt;h3&gt;
  
  
  Navegador web: botón de "atrás"
&lt;/h3&gt;

&lt;p&gt;Cada vez que visitas una página nueva, el navegador hace &lt;code&gt;push()&lt;/code&gt; con la URL. Cuando presionas "atrás", hace &lt;code&gt;pop()&lt;/code&gt; y te lleva a la página anterior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g3uc6zt7do2joho3d27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6g3uc6zt7do2joho3d27.png" alt="Historial del navegador como stack" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Funciona perfecto porque siempre quieres volver a la última página que visitaste, no a una del medio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ctrl + Z: deshacer acciones
&lt;/h3&gt;

&lt;p&gt;Cuando escribes en un editor de texto, cada acción (escribir una letra, borrar, pegar) se agrega a un stack. Cuando presionas &lt;code&gt;Ctrl + Z&lt;/code&gt;, la última acción se hace &lt;code&gt;pop()&lt;/code&gt; y se deshace. Presionas &lt;code&gt;Ctrl + Z&lt;/code&gt; otra vez y la penúltima se deshace.&lt;/p&gt;

&lt;p&gt;Mismo patrón: siempre deshaces la acción más reciente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Call stack de tu programa
&lt;/h3&gt;

&lt;p&gt;Cuando una función llama a otra, que a su vez llama a otra, tu programa va apilando cada llamada en un "call stack". Cuando una función termina, se hace &lt;code&gt;pop()&lt;/code&gt; y el control vuelve a la función anterior.&lt;/p&gt;

&lt;p&gt;Por eso cuando ves un error con "stack trace" en la consola, estás viendo exactamente eso: el estado del stack de llamadas en el momento del error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validación de paréntesis balanceados
&lt;/h3&gt;

&lt;p&gt;Un problema clásico de entrevistas. ¿Cómo verificas que en &lt;code&gt;((a + b) * (c - d))&lt;/code&gt; todos los paréntesis estén correctamente balanceados? Con un stack. Cada &lt;code&gt;(&lt;/code&gt; hace push, cada &lt;code&gt;)&lt;/code&gt; hace pop. Si al final el stack está vacío, los paréntesis están balanceados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cierre
&lt;/h2&gt;

&lt;p&gt;Los stacks son simples: cinco métodos, todos O(1), un solo principio (LIFO). Y justo por eso los encuentras en tantos lugares, desde el botón de atrás hasta el call stack de tu lenguaje de programación.&lt;/p&gt;

&lt;p&gt;Si te sirvió el artículo, dale ❤️ y sígueme para no perderte el siguiente. Nos leemos pronto. 🙌🏻&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>computerscience</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Two Pointers en entrevistas técnicas: 3 problemas resueltos</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Wed, 22 Apr 2026 20:31:27 +0000</pubDate>
      <link>https://dev.to/aws/two-pointers-en-entrevistas-tecnicas-3-problemas-resueltos-324n</link>
      <guid>https://dev.to/aws/two-pointers-en-entrevistas-tecnicas-3-problemas-resueltos-324n</guid>
      <description>&lt;p&gt;Si estás preparándote para entrevistas técnicas, tarde o temprano vas a encontrarte con problemas de arrays y strings. Y varios se resuelven con una misma familia de técnicas: two pointers.&lt;/p&gt;

&lt;p&gt;En los artículos anteriores vimos &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;cómo funcionan los arrays&lt;/a&gt; y &lt;a href="https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd"&gt;los strings&lt;/a&gt; por debajo: memoria contigua, acceso por índice, operaciones y sus costos. Hoy toca usar todo eso para resolver problemas reales.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lo que vas a encontrar en este artículo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué son las entrevistas técnicas y por qué te piden resolver problemas&lt;/li&gt;
&lt;li&gt;Qué es two pointers y qué técnicas incluye&lt;/li&gt;
&lt;li&gt;Cómo identificar cuál técnica usar&lt;/li&gt;
&lt;li&gt;Un problema resuelto paso a paso por cada técnica&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué son los problemas de entrevistas técnicas?
&lt;/h2&gt;

&lt;p&gt;Son ejercicios de programación que te ponen en entrevistas para puestos de desarrollo de software. Ojo, las entrevistas técnicas existen para muchos roles (arquitectura, DevOps, SRE, developer) y no todas se ven igual. Este artículo se enfoca en las entrevistas para roles de developer.&lt;/p&gt;

&lt;p&gt;El objetivo no es que te sepas la respuesta de memoria. Lo que evalúan es cómo piensas: cómo descompones un problema, qué estructura de datos eliges y si tu solución es eficiente.&lt;/p&gt;

&lt;p&gt;Y aquí viene lo interesante: existen técnicas que se crearon específicamente para resolver estos problemas de forma óptima. No es magia, es práctica y reconocimiento de patrones.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es Two Pointers?
&lt;/h2&gt;

&lt;p&gt;Two pointers es un paradigma general para resolver problemas con arrays y strings. La idea es simple: usas dos variables (los "punteros") que recorren la estructura de datos de formas específicas.&lt;/p&gt;

&lt;p&gt;Ojo, cuando digo "punteros" no me refiero a punteros de memoria como en C. Aquí son simplemente variables que guardan índices para acceder a posiciones del array o string.&lt;/p&gt;

&lt;p&gt;¿Por qué funciona? Porque con dos punteros moviéndose de forma inteligente, puedes evitar soluciones de fuerza bruta O(n²) y resolverlo en O(n). Eso es exactamente lo que buscan en una entrevista.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué técnicas incluye?
&lt;/h3&gt;

&lt;p&gt;Two pointers incluye tres variantes principales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast and slow pointers&lt;/strong&gt; (lento y rápido): un puntero explora y otro se queda marcando una posición.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opposite direction pointers&lt;/strong&gt; (punteros convergentes): empiezan en los extremos y se acercan al centro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel pointers&lt;/strong&gt; (punteros paralelos): cada puntero recorre un array diferente al mismo tiempo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lo que todas tienen en común: usan al menos 2 variables para recorrer un arreglo o string, y nos ayudan a pasar de O(n²) a O(n).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vamos a usar los nombres en inglés porque así los encuentras en la mayoría de recursos, LeetCode y entrevistas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ¿Cómo saber cuál técnica usar?
&lt;/h3&gt;

&lt;p&gt;Antes de entrar a los problemas, una guía rápida. Si en el enunciado ves algo de esto, probablemente necesitas two pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Te dan uno o dos arreglos/strings.&lt;/li&gt;
&lt;li&gt;Te piden espacio O(1) o modificar el array en su lugar.&lt;/li&gt;
&lt;li&gt;La solución obvia sería O(n²) pero necesitas algo mejor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora, ¿cuál variante? Aquí va un resumen:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Técnica&lt;/th&gt;
&lt;th&gt;Úsala cuando...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fast and slow&lt;/td&gt;
&lt;td&gt;Necesitas comparar o modificar elementos dentro del mismo array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opposite direction&lt;/td&gt;
&lt;td&gt;Necesitas verificar propiedades simétricas, encontrar pares, o trabajar desde los extremos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel pointers&lt;/td&gt;
&lt;td&gt;Tienes dos arrays y necesitas compararlos o fusionarlos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sé que puede parecer mucho, pero conforme resolvamos los problemas vas a ver que es más intuitivo de lo que parece. Vamos a eso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opposite direction: Verificar un palíndromo
&lt;/h2&gt;

&lt;p&gt;Empecemos con opposite direction porque es la más visual.&lt;/p&gt;

&lt;p&gt;Tomemos el problema &lt;a href="https://leetcode.com/problems/valid-palindrome/description/" rel="noopener noreferrer"&gt;"Valid Palindrome" de LeetCode&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Una frase es un palíndromo si, tras convertir todas las letras a minúsculas y eliminar los caracteres no alfanuméricos, se lee igual de izquierda a derecha que de derecha a izquierda.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dada una cadena &lt;code&gt;s&lt;/code&gt;, devuelve &lt;code&gt;true&lt;/code&gt; si es un palíndromo, o &lt;code&gt;false&lt;/code&gt; en caso contrario.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  s = "A man, a plan, a canal: Panama"
Output: true
// Porque "amanaplanacanalpanama" se lee igual en ambas direcciones

Input:  s = "race a car"
Output: false
// Porque "raceacar" no es palíndromo

Input:  s = " "
Output: true
// Un string vacío se lee igual al derecho y al revés
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;La solución de fuerza bruta sería limpiar el string, invertirlo y comparar. Funciona, pero crea strings nuevos en memoria (recuerda que los strings son inmutables, así que cada operación crea uno nuevo).&lt;/p&gt;

&lt;p&gt;Con opposite direction pointers hacemos algo más elegante: ponemos un puntero al inicio y otro al final. Los vamos acercando al centro comparando los caracteres. Si en algún momento no coinciden, no es palíndromo. Si los punteros se cruzan sin encontrar diferencias, sí lo es.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución paso a paso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {string} s
 * @return {boolean}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;isPalindrome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isAlphanumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isAlphanumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// función auxiliar: ¿es letra o número?&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAlphanumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="c1"&gt;// 0-9&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="c1"&gt;// A-Z&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;97&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// a-z&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos línea por línea:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; arranca en &lt;code&gt;0&lt;/code&gt; (inicio del string) y &lt;code&gt;r&lt;/code&gt; en &lt;code&gt;s.length - 1&lt;/code&gt; (final). Son nuestros dos punteros que se van a acercar al centro.&lt;/li&gt;
&lt;li&gt;El &lt;code&gt;while (l &amp;lt; r)&lt;/code&gt; se ejecuta mientras los punteros no se hayan cruzado.&lt;/li&gt;
&lt;li&gt;Dentro del loop hay cuatro casos:

&lt;ul&gt;
&lt;li&gt;Si &lt;code&gt;s[l]&lt;/code&gt; no es alfanumérico (un espacio, coma, dos puntos...), lo saltamos moviendo &lt;code&gt;l&lt;/code&gt; a la derecha.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;s[r]&lt;/code&gt; no es alfanumérico, lo saltamos moviendo &lt;code&gt;r&lt;/code&gt; a la izquierda.&lt;/li&gt;
&lt;li&gt;Si ambos son alfanuméricos pero no coinciden (comparando en minúsculas), no es palíndromo. Retornamos &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si coinciden, avanzamos ambos punteros hacia el centro (&lt;code&gt;l++&lt;/code&gt;, &lt;code&gt;r--&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Si el loop termina sin retornar &lt;code&gt;false&lt;/code&gt;, los punteros se cruzaron sin encontrar diferencias. Es palíndromo, retornamos &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La función auxiliar &lt;code&gt;isAlphanumeric&lt;/code&gt; &lt;a href="https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5"&gt;revisa el código ASCII del carácter&lt;/a&gt;: &lt;code&gt;48-57&lt;/code&gt; son dígitos, &lt;code&gt;65-90&lt;/code&gt; letras mayúsculas, &lt;code&gt;97-122&lt;/code&gt; letras minúsculas. Todo lo demás (espacios, puntuación, etc.) retorna &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Complejidad: O(n) en tiempo, O(1) en espacio. Un solo recorrido del string, sin crear copias ni estructuras extra.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Veamos cómo se ve con &lt;code&gt;s = "A man, a plan, a canal: Panama"&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8e5tzx2idnwpgti20buy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8e5tzx2idnwpgti20buy.png" alt="Paso a paso de opposite direction pointers para validar un palíndromo" width="800" height="957"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast and slow: Remove Duplicates
&lt;/h2&gt;

&lt;p&gt;Ahora veamos fast and slow con el clásico &lt;a href="https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/" rel="noopener noreferrer"&gt;"Remove Duplicates from Sorted Array" de LeetCode&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br&gt;
Te dan una lista de números &lt;code&gt;nums&lt;/code&gt; ya ordenada de menor a mayor, pero con algunos repetidos. Tienes que dejar cada número una sola vez, moviendo los únicos al inicio de la misma lista (sin crear otra lista nueva).&lt;br&gt;
Por ejemplo, si te dan &lt;code&gt;[1, 1, 2, 3, 3]&lt;/code&gt;, la lista debe quedar así: &lt;code&gt;[1, 2, 3, ?, ?]&lt;/code&gt;. Los primeros tres espacios tienen los números únicos en orden, y los últimos dos espacios no importan (pueden quedar con cualquier valor, por eso los marcamos con &lt;code&gt;?&lt;/code&gt;).&lt;br&gt;
Además, tu función debe devolver cuántos números únicos quedaron al inicio. En el ejemplo anterior, devolverías &lt;code&gt;3&lt;/code&gt; porque hay tres números únicos (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;). A ese número lo llaman &lt;code&gt;k&lt;/code&gt; en el enunciado.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ejemplo 1

Entrada: nums = [1,1,2]
Salida: 2, nums = [1,2,_]

Explicación: Tu función debe devolver k = 2, y los primeros dos elementos de nums deben ser 1 y 2 respectivamente. No importa qué quede después de los primeros k espacios (por eso aparecen como guiones bajos).

Ejemplo 2

Entrada: nums = [0,0,1,1,1,2,2,3,3,4]
Salida: 5, nums = [0,1,2,3,4,_,_,_,_,_]

Explicación: Tu función debe devolver k = 5, y los primeros cinco elementos de nums deben ser 0, 1, 2, 3 y 4 respectivamente. No importa qué quede después de los primeros k espacios (por eso aparecen como guiones bajos).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;La fuerza bruta sería crear un nuevo array y copiar solo los valores que no se repiten. Pero el problema dice explícitamente que lo hagas "in-place", o sea, modificando el mismo array sin crear otro. Ahí es donde entra fast and slow.&lt;/p&gt;

&lt;p&gt;La idea es esta: usamos dos punteros que arrancan casi juntos. &lt;code&gt;slow&lt;/code&gt; marca la posición donde va el siguiente número único. &lt;code&gt;fast&lt;/code&gt; se adelanta recorriendo todo el array buscando valores nuevos.&lt;/p&gt;

&lt;p&gt;Como el array ya está ordenado, los duplicados siempre están juntos. Entonces &lt;code&gt;fast&lt;/code&gt; solo necesita comparar su valor con el de &lt;code&gt;slow&lt;/code&gt;. Si son diferentes, encontramos un número nuevo: avanzamos &lt;code&gt;slow&lt;/code&gt; una posición y copiamos ahí el valor de &lt;code&gt;fast&lt;/code&gt;. Si son iguales, &lt;code&gt;fast&lt;/code&gt; simplemente sigue avanzando.&lt;/p&gt;

&lt;p&gt;Piénsalo así: &lt;code&gt;slow&lt;/code&gt; es el que construye la respuesta, y &lt;code&gt;fast&lt;/code&gt; es el explorador que le dice "oye, encontré uno nuevo".&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución paso a paso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number[]} nums
 * @return {number}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;removeDuplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos línea por línea:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;slow&lt;/code&gt; arranca en &lt;code&gt;0&lt;/code&gt;, apuntando al primer elemento. Ese siempre es único porque no hay nada antes con qué comparar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fast&lt;/code&gt; arranca en &lt;code&gt;1&lt;/code&gt; y recorre el array completo con el &lt;code&gt;for&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;En cada paso, comparamos &lt;code&gt;nums[fast]&lt;/code&gt; con &lt;code&gt;nums[slow]&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;Si son &lt;strong&gt;iguales&lt;/strong&gt;, es un duplicado. &lt;code&gt;fast&lt;/code&gt; avanza y &lt;code&gt;slow&lt;/code&gt; se queda donde está. No hacemos nada.&lt;/li&gt;
&lt;li&gt;Si son &lt;strong&gt;diferentes&lt;/strong&gt;, encontramos un valor nuevo. Avanzamos &lt;code&gt;slow&lt;/code&gt; una posición (&lt;code&gt;slow++&lt;/code&gt;) y copiamos el valor de &lt;code&gt;fast&lt;/code&gt; ahí (&lt;code&gt;nums[slow] = nums[fast]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Al final, &lt;code&gt;slow&lt;/code&gt; queda apuntando al último elemento único. Como los índices empiezan en &lt;code&gt;0&lt;/code&gt;, el total de únicos es &lt;code&gt;slow + 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Veamos cómo se ve con &lt;code&gt;nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc29qo1ge8gmobk34f4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc29qo1ge8gmobk34f4g.png" alt="Ejemplo visual de fast and slow pointers eliminando duplicados en un array ordenado" width="800" height="1560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los primeros 5 elementos son &lt;code&gt;[0, 1, 2, 3, 4]&lt;/code&gt;, exactamente los valores únicos en orden. Lo que queda después del índice 4 no importa.&lt;/p&gt;

&lt;p&gt;¿Ves el patrón? &lt;code&gt;fast&lt;/code&gt; recorre todo el array una sola vez, y &lt;code&gt;slow&lt;/code&gt; solo avanza cuando encuentra algo nuevo. Eso nos da O(n) en tiempo y O(1) en espacio, porque no creamos ninguna estructura extra.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Complejidad: O(n) en tiempo, O(1) en espacio. Un solo recorrido, sin estructuras extra.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Parallel pointers: Intersección de dos arrays
&lt;/h2&gt;

&lt;p&gt;Por último, parallel pointers con &lt;a href="https://leetcode.com/problems/intersection-of-two-arrays/description/" rel="noopener noreferrer"&gt;"Intersection of Two Arrays" de LeetCode&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Dados dos arreglos de enteros, devuelve un arreglo con su intersección. Cada elemento del resultado debe ser único y puede estar en cualquier orden.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  nums1 = [1, 2, 2, 1], nums2 = [2, 2]
Output: [2]

Input:  nums1 = [4, 9, 5], nums2 = [9, 4, 9, 8, 4]
Output: [9, 4]  // el orden no importa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;La fuerza bruta sería usar dos loops anidados: por cada elemento de &lt;code&gt;nums1&lt;/code&gt;, recorrer todo &lt;code&gt;nums2&lt;/code&gt; buscando coincidencias.&lt;/p&gt;

&lt;p&gt;Con parallel pointers hacemos algo más inteligente: primero ordenamos ambos arrays y después los recorremos una sola vez con dos punteros. Como están ordenados, podemos comparar los valores y decidir cuál puntero mover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si los valores son iguales, encontramos una intersección. Avanzamos ambos.&lt;/li&gt;
&lt;li&gt;Si el valor de &lt;code&gt;p1&lt;/code&gt; es menor, lo avanzamos porque no puede haber coincidencia más atrás en &lt;code&gt;nums2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si el valor de &lt;code&gt;p2&lt;/code&gt; es menor, lo avanzamos por la misma razón.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Es como hacer merge de dos listas ordenadas, pero solo nos quedamos con los valores que aparecen en ambas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución paso a paso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;intersection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ordenar arreglos&lt;/span&gt;
  &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intersection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Evita duplicados en el resultado&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos línea por línea:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ordenamos ambos arrays con &lt;code&gt;.sort()&lt;/code&gt;. Esto es clave: sin el orden, no podríamos saber hacia dónde mover los punteros.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p1&lt;/code&gt; y &lt;code&gt;p2&lt;/code&gt; arrancan en &lt;code&gt;0&lt;/code&gt;, cada uno apuntando al inicio de su array.&lt;/li&gt;
&lt;li&gt;El &lt;code&gt;while&lt;/code&gt; se ejecuta mientras ambos punteros estén dentro de sus arrays.&lt;/li&gt;
&lt;li&gt;Dentro del loop hay tres casos:

&lt;ul&gt;
&lt;li&gt;Si &lt;code&gt;nums1[p1] === nums2[p2]&lt;/code&gt;, encontramos un valor en común. Antes de agregarlo, verificamos que no sea un duplicado (comparando con el último elemento del resultado). Avanzamos ambos punteros.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;nums1[p1] &amp;lt; nums2[p2]&lt;/code&gt;, el valor de &lt;code&gt;p1&lt;/code&gt; es más chico. Como ambos arrays están ordenados, ese valor no puede existir más adelante en &lt;code&gt;nums2&lt;/code&gt;. Avanzamos &lt;code&gt;p1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;nums1[p1] &amp;gt; nums2[p2]&lt;/code&gt;, misma lógica pero al revés. Avanzamos &lt;code&gt;p2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cuando alguno de los dos punteros llega al final de su array, el loop termina. Ya no puede haber más intersecciones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Veamos con &lt;code&gt;nums1 = [4, 9, 5]&lt;/code&gt;, &lt;code&gt;nums2 = [9, 4, 9, 8, 4]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbm7ndbv01ljj53pjttd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbm7ndbv01ljj53pjttd.png" alt="Ejemplo de parallel pointers encontrando la intersección de dos arrays" width="800" height="1362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Ves cómo cada puntero solo avanza hacia adelante? Nunca retroceden. El recorrido en sí es O(n + m), pero el ordenamiento inicial domina: O(n log n + m log m) en total.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Complejidad: O(n log n + m log m) en tiempo por el ordenamiento. O(n) en espacio para el resultado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Resumen
&lt;/h2&gt;

&lt;p&gt;Estas tres técnicas son variantes de un mismo concepto: usar dos punteros para recorrer arrays o strings de forma eficiente.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Técnica&lt;/th&gt;
&lt;th&gt;Movimiento de punteros&lt;/th&gt;
&lt;th&gt;Problema resuelto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Opposite direction&lt;/td&gt;
&lt;td&gt;De los extremos al centro&lt;/td&gt;
&lt;td&gt;Valid Palindrome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fast and slow&lt;/td&gt;
&lt;td&gt;Uno explora, otro referencia&lt;/td&gt;
&lt;td&gt;Remove Duplicates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel pointers&lt;/td&gt;
&lt;td&gt;Cada uno en su array&lt;/td&gt;
&lt;td&gt;Intersection of Two Arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzino3kb155ixt357afde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzino3kb155ixt357afde.png" alt="Árbol de decisión para elegir la variante de two pointers" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La clave no es memorizar las soluciones. Es reconocer el patrón en el enunciado y saber qué técnica aplicar. Con práctica, vas a leer un problema y saber qué variante de two pointers usar antes de escribir una línea de código.&lt;/p&gt;

&lt;p&gt;Si quieres seguir practicando, aquí te dejo más problemas de LeetCode:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/valid-anagram/description/" rel="noopener noreferrer"&gt;Valid Anagram&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/explore/learn/card/fun-with-arrays/527/searching-for-items-in-an-array/3250/" rel="noopener noreferrer"&gt;Check If N and Its Double Exist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/explore/learn/card/fun-with-arrays/511/searching-for-items-in-an-array/3157/" rel="noopener noreferrer"&gt;Move Zeroes&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;¿Cuál técnica te costó más entender? ¿Hay algún problema que quieras que resolvamos juntos? Déjamelo en los comentarios. 🙌🏻&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>spanish</category>
    </item>
    <item>
      <title>No olvides revisar estos consejos para disminuir la probabilidad de infectar tu computadora con un troyano al instalar un paquete de npm.</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Thu, 16 Apr 2026 18:03:35 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/no-olvides-revisar-estos-consejos-para-disminuir-la-probabilidad-de-infectar-tu-computadora-con-un-2k6h</link>
      <guid>https://dev.to/fromchiapasdev/no-olvides-revisar-estos-consejos-para-disminuir-la-probabilidad-de-infectar-tu-computadora-con-un-2k6h</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" class="crayons-story__hidden-navigation-link"&gt;npm install puede infectar tu máquina: cómo protegerte&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/fromchiapasdev" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186583%2F9cef57b1-206b-4316-9880-0fe5907f987f.jpeg" alt="fromchiapasdev profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/fromchiapasdev" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Axel Espinosa
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Axel Espinosa
                
              
              &lt;div id="story-author-preview-content-3452405" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/fromchiapasdev" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186583%2F9cef57b1-206b-4316-9880-0fe5907f987f.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Axel Espinosa&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" id="article-link-3452405"&gt;
          npm install puede infectar tu máquina: cómo protegerte
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/discuss"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;discuss&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/npm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;npm&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/node"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;node&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>🙌🏻</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Wed, 15 Apr 2026 16:25:01 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/-2ai7</link>
      <guid>https://dev.to/fromchiapasdev/-2ai7</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" class="crayons-story__hidden-navigation-link"&gt;Cómo crear un agente de IA desde cero. Open source, local y gratis.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/aws"&gt;
            &lt;img alt="AWS logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1726%2F2a73f1e6-7995-4348-ae37-44b064274c59.png" class="crayons-logo__image" width="320" height="320"&gt;
          &lt;/a&gt;

          &lt;a href="/hsaenzg" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F852908%2Fa3a10986-307b-4a35-8adf-eeb9a583e6a9.jpg" alt="hsaenzg profile" class="crayons-avatar__image" width="800" height="1067"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hsaenzg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Hazel Saenz
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Hazel Saenz
                
              
              &lt;div id="story-author-preview-content-3506071" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hsaenzg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F852908%2Fa3a10986-307b-4a35-8adf-eeb9a583e6a9.jpg" class="crayons-avatar__image" alt="" width="800" height="1067"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Hazel Saenz&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/aws" class="crayons-story__secondary fw-medium"&gt;AWS&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" id="article-link-3506071"&gt;
          Cómo crear un agente de IA desde cero. Open source, local y gratis.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/agents"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;agents&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            14 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>¿Qué es un String y para qué sirven?</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Mon, 13 Apr 2026 21:19:53 +0000</pubDate>
      <link>https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd</link>
      <guid>https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd</guid>
      <description>&lt;p&gt;Los strings son probablemente la estructura de datos que más usas sin pensar. Pero, ¿sabes cómo se almacenan en memoria? ¿Por qué no puedes modificarlos directamente? ¿Cuánto cuesta concatenarlos en un loop?&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;artículo anterior&lt;/a&gt; vimos cómo funcionan los arrays por debajo: memoria contigua, acceso por índice, operaciones y sus costos. Si aún no lo has leído, te recomiendo empezar por ahí. Hoy toca hablar de sus primos: los strings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En estos ejemplos usaremos JavaScript como lenguaje principal. Si usas otro lenguaje, te invito a buscar los métodos equivalentes. Los conceptos son los mismos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo que encontrarás en este artículo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué es un string y cómo se almacena en memoria&lt;/li&gt;
&lt;li&gt;Qué significa que sean inmutables&lt;/li&gt;
&lt;li&gt;En qué se parecen y en qué se diferencian de los arrays&lt;/li&gt;
&lt;li&gt;Operaciones comunes con strings y cuánto cuestan (Big O)&lt;/li&gt;
&lt;li&gt;Una tabla de complejidad para que la tengas de referencia&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. ¿Qué es un string?
&lt;/h2&gt;

&lt;p&gt;Un string (o cadena de caracteres) es una secuencia de caracteres almacenados de forma contigua en memoria. Suena familiar, ¿verdad? Es básicamente lo que vimos con los &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;arrays&lt;/a&gt;, pero en lugar de números o emojis, almacenamos caracteres.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Índice:    0   1   2   3   4
         ┌───┬───┬───┬───┬───┐
String:  │ H │ o │ l │ a │ ! │
         └───┴───┴───┴───┴───┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para empezar, puedes pensar en un string como un array de caracteres — es un buen modelo mental. Más adelante verás que los motores modernos implementan strings con estructuras más sofisticadas, pero conceptualmente esta idea te va a servir para entender cómo se comportan.&lt;/p&gt;

&lt;p&gt;Pero aquí viene el detalle: ¿qué es realmente un "carácter" para la computadora? No es una letra. Es un número. La "H" es el 72, la "o" es el 111. Cada carácter tiene un código numérico asignado por un estándar (como ASCII o Unicode), y un encoding (como UTF-8) convierte ese código a bits. Así que cuando digo "array de caracteres", por debajo es un array de números.&lt;/p&gt;

&lt;p&gt;Si quieres entender a fondo cómo funciona eso, lo cubrimos en el &lt;a href="https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5"&gt;artículo de encodings&lt;/a&gt;. Ahí explicamos por qué un emoji ocupa 4 bytes y una letra solo 1. 😉&lt;/p&gt;

&lt;p&gt;Cada carácter ocupa una posición y tiene un índice, exactamente como en un array. Y al igual que con los &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;arrays&lt;/a&gt;, acceder a un carácter por su índice es instantáneo: O(1).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saludo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "H"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Una advertencia importante:&lt;/strong&gt; este modelo funciona perfectamente con caracteres del alfabeto latino básico, pero se complica con emojis y algunos caracteres especiales. En JavaScript, un emoji como 😀 ocupa &lt;strong&gt;dos posiciones&lt;/strong&gt; en el string, no una:&lt;/p&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;😀&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 2, no 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Esto es por cómo JavaScript representa internamente el texto (UTF-16). Lo vemos a detalle en el &lt;a href="https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5"&gt;artículo de encodings&lt;/a&gt;. Por ahora, si trabajas con caracteres simples, el modelo de "array de caracteres" te sirve bien.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. ¿Por qué los strings son inmutables?
&lt;/h2&gt;

&lt;p&gt;Porque una vez que creas un string, su contenido no puede cambiar. Si necesitas una versión diferente, se crea uno nuevo en memoria. Esto aplica en JavaScript, Python y la mayoría de lenguajes modernos. Aquí es donde los strings empiezan a diferenciarse de los arrays.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué significa inmutable?
&lt;/h3&gt;

&lt;p&gt;Inmutable quiere decir que algo no puede cambiar después de creado. En programación, cuando decimos que un valor es inmutable, significa que no puedes modificar su contenido directamente. Si necesitas una versión diferente, tienes que crear una nueva.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué pasa cuando modificas un string?
&lt;/h3&gt;

&lt;p&gt;En lenguajes como JavaScript y Python, los strings son inmutables. Esto quiere decir que cuando "modificas" un string, en realidad se está creando uno nuevo en memoria. El original no se toca.&lt;/p&gt;

&lt;p&gt;Veamos un ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;palabra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;palabra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;J&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Intentamos cambiar la "H" por "J"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;palabra&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Hola" — no cambió nada&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Ves? JavaScript simplemente ignora el intento. No lanza un error, pero tampoco hace el cambio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si tu código está en strict mode (lo cual pasa automáticamente dentro de módulos ES y clases), este intento sí lanza un &lt;code&gt;TypeError&lt;/code&gt;. Es el comportamiento más común en código moderno.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En Python es más explícito:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;palabra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hola&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;palabra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;J&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# TypeError: 'str' object does not support item assignment
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python directamente te dice: "no puedes hacer eso".&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuánto cuesta concatenar strings?
&lt;/h3&gt;

&lt;p&gt;Cuando concatenas strings con &lt;code&gt;+=&lt;/code&gt;, no estás "agregando" al final como harías con &lt;code&gt;push()&lt;/code&gt; en un array. Conceptualmente, se crea un string nuevo que contiene todo el contenido anterior más lo que agregaste.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Se crea un nuevo string "Hola"&lt;/span&gt;
&lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Se crea un nuevo string "Hola "&lt;/span&gt;
&lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mundo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Se crea un nuevo string "Hola Mundo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Construir un string de tamaño N con concatenaciones repetidas tiene un costo total de O(N) — el tamaño del resultado final.&lt;/p&gt;

&lt;p&gt;Los motores de JavaScript modernos optimizan este caso con estructuras internas que evitan copiar el string completo en cada paso, así que en la práctica &lt;code&gt;+=&lt;/code&gt; en un loop es bastante eficiente. Pero la regla general sigue siendo útil: si vas a construir texto pieza por pieza, piensa en el tamaño del resultado final, no solo en cuántas piezas tienes.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. ¿Cuál es la diferencia entre strings y arrays?
&lt;/h2&gt;

&lt;p&gt;Ambos son secuencias contiguas con acceso por índice O(1), pero los arrays son mutables y los strings no. Esa diferencia cambia todo: los arrays tienen &lt;code&gt;push&lt;/code&gt; y &lt;code&gt;pop&lt;/code&gt;, los strings tienen métodos de texto como &lt;code&gt;slice&lt;/code&gt;, &lt;code&gt;split&lt;/code&gt; y &lt;code&gt;replace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Primos, no gemelos. Los arrays te permiten modificar su contenido directamente: cambiar un elemento por índice, agregar al final, quitar del inicio. Los strings no. Son inmutables, así que no puedes hacer &lt;code&gt;push&lt;/code&gt; o &lt;code&gt;pop&lt;/code&gt; sobre un string.&lt;/p&gt;

&lt;p&gt;Lo que sí tienen los strings son métodos especializados para operaciones comunes con texto: buscar, acortar, dividir, reemplazar. Implementar estos métodos de strings manualmente sería tedioso (y propenso a errores). Por eso los lenguajes nos dan estos métodos listos para usar.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;Array (dinámico)&lt;/th&gt;
&lt;th&gt;String&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Secuencia contigua&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acceso por índice&lt;/td&gt;
&lt;td&gt;✅ O(1)&lt;/td&gt;
&lt;td&gt;✅ O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mutable&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;push / pop&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Métodos de texto&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ (search, slice, split, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redimensionable&lt;/td&gt;
&lt;td&gt;✅ (crece automáticamente)&lt;/td&gt;
&lt;td&gt;❌ (se crea uno nuevo)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4. Operaciones comunes con strings y su complejidad
&lt;/h2&gt;

&lt;p&gt;Vamos a las operaciones que más vas a usar con strings. Cada una con un ejemplo en JavaScript y su complejidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Obtener longitud
&lt;/h3&gt;

&lt;p&gt;Igual que con los arrays, podemos saber cuántos caracteres tiene un string con &lt;code&gt;.length&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola Mundo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(1)&lt;/strong&gt; — el acceso es inmediato&lt;/p&gt;

&lt;h3&gt;
  
  
  Acceso por índice
&lt;/h3&gt;

&lt;p&gt;Ya lo vimos, pero vale la pena repetirlo: puedes acceder a cualquier carácter directamente por su posición.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "J"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "S"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(1)&lt;/strong&gt; — acceso directo, como el elevador del artículo de arrays.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buscar dentro de un string
&lt;/h3&gt;

&lt;p&gt;Podemos verificar si un string contiene cierto texto con &lt;code&gt;includes()&lt;/code&gt;, o encontrar la posición exacta con &lt;code&gt;indexOf()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Los arrays son geniales&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arrays&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arrays&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// -1 (no lo encontró)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n·m) en el peor caso&lt;/strong&gt; — donde &lt;code&gt;n&lt;/code&gt; es la longitud del string y &lt;code&gt;m&lt;/code&gt; la longitud del texto que buscas. En la práctica, los motores modernos usan algoritmos de búsqueda optimizados que son mucho más rápidos en la mayoría de los casos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extraer una porción (slice / substring)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;slice()&lt;/code&gt; te permite extraer una parte del string sin modificar el original (recuerda: inmutabilidad).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Java"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Script"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// string original&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n) en el peor caso&lt;/strong&gt; — donde &lt;code&gt;n&lt;/code&gt; es el tamaño de la porción extraída. Algunos motores optimizan esta operación para evitar copiar cuando es posible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dividir un string (split)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;split()&lt;/code&gt; divide un string en un array de substrings usando un separador.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nombre,edad,ciudad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;campos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;campos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ["nombre", "edad", "ciudad"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n)&lt;/strong&gt; — recorre todo el string para encontrar los separadores y crear los substrings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concatenar strings
&lt;/h3&gt;

&lt;p&gt;Ya hablamos de esto, pero aquí va el resumen con código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nombre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saludo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nombre&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; Mundo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Hola Mundo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n)&lt;/strong&gt; — donde &lt;code&gt;n&lt;/code&gt; es el tamaño del resultado final. Recuerda que los motores modernos optimizan esta operación por debajo.&lt;/p&gt;

&lt;p&gt;Si quieres explorar todos los métodos de strings disponibles en JavaScript, la &lt;a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/String" rel="noopener noreferrer"&gt;referencia de String en MDN&lt;/a&gt; es un excelente recurso.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. ¿Cuál es la complejidad Big O de las operaciones con strings?
&lt;/h2&gt;

&lt;p&gt;Aquí te dejo la tabla de complejidad, en el mismo formato que usamos en el artículo de arrays para que puedas compararlas:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operación&lt;/th&gt;
&lt;th&gt;Complejidad&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Acceso por índice&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Obtener longitud&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buscar un substring&lt;/td&gt;
&lt;td&gt;O(n·m)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concatenar (resultado total)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slice / Substring&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; las complejidades de búsqueda y concatenación representan el &lt;strong&gt;peor caso&lt;/strong&gt;. Los motores modernos de JavaScript implementan optimizaciones que hacen que en la práctica sean más rápidas de lo que sugiere la teoría.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Compara esta tabla con la del &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;artículo de arrays&lt;/a&gt;. Vas a notar que el acceso por índice es igual de rápido en ambos. La diferencia está en que los strings no tienen operaciones como &lt;code&gt;push&lt;/code&gt; o &lt;code&gt;pop&lt;/code&gt; porque son inmutables. Cada vez que necesitas un string "modificado", estás pagando el costo de crear uno nuevo.&lt;/p&gt;

&lt;p&gt;Algo importante: en esta tabla y a lo largo del artículo usamos Big O para describir el costo de las operaciones. Big O es una notación que nos dice cómo crece el tiempo de una operación conforme crece el tamaño de la entrada. O(1) significa tiempo constante (siempre tarda lo mismo sin importar el tamaño), y O(n) significa tiempo lineal (entre más grande la entrada, más tarda, proporcionalmente).&lt;/p&gt;

&lt;p&gt;No es el foco de este artículo, pero es importante que tengas el contexto. Si quieres que hagamos un artículo dedicado a Big O, dime en los comentarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Los strings son como los primos de los arrays: comparten la misma base (secuencia contigua, acceso por índice) pero juegan con reglas diferentes gracias a la inmutabilidad. Eso los hace predecibles y seguros, pero también significa que operaciones que parecen simples, como concatenar en un loop, pueden ser más costosas de lo que esperabas.&lt;/p&gt;

&lt;p&gt;Si leíste con atención, quizá notaste que dije varias veces "en el peor caso". Eso es porque los motores de JavaScript modernos hacen optimizaciones que a veces rompen el modelo mental simple que vimos aquí.&lt;/p&gt;

&lt;p&gt;En el siguiente artículo de la serie vamos a poner en práctica todo lo que hemos visto de arrays y strings con problemas y patrones comunes de entrevistas técnicas. Ahí es donde todo se conecta. 💪&lt;/p&gt;

&lt;p&gt;Si quieres avanzar con el siguiente tema intenta resolver esto: &lt;em&gt;dado un string, ¿cómo lo invertirías sin usar &lt;code&gt;.reverse()&lt;/code&gt;? Piensa en lo que vimos de inmutabilidad&lt;/em&gt;. En el siguiente artículo vamos a resolver este tipo de problemas.&lt;/p&gt;

&lt;p&gt;Gracias por llegar hasta el final. Estaré pendiente de tus comentarios 🙌🏻&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>español</category>
    </item>
    <item>
      <title>npm install puede infectar tu máquina: cómo protegerte</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Sat, 04 Apr 2026 05:57:09 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea</link>
      <guid>https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea</guid>
      <description>&lt;p&gt;Haces &lt;code&gt;npm install&lt;/code&gt;, confías en que todo está bien, y sin saberlo un script malicioso ya se ejecutó en tu máquina. Así funcionan los ataques de supply chain en npm: infectan paquetes populares (o sus dependencias) y usan los lifecycle scripts para correr código antes de que te des cuenta.&lt;/p&gt;

&lt;p&gt;Este tipo de ataque se viene hablando desde el 2022 pero los atacantes lo han utilizado con mayor frecuencia debido al alcance que logran tener en el ecosistema de npm. Un ejemplo reciente: &lt;a href="https://www.microsoft.com/en-us/security/blog/2025/12/09/shai-hulud-2-0-guidance-for-detecting-investigating-and-defending-against-the-supply-chain-attack/" rel="noopener noreferrer"&gt;Shai Hulud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En este post te explico cómo funcionan estos ataques y qué configuraciones puedes aplicar hoy para proteger tus proyectos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un "supply chain attack" o ataque a la cadena de suministro?
&lt;/h2&gt;

&lt;p&gt;Este tipo de ataque se caracteriza por infectar alguna parte del ciclo de entrega del software.&lt;br&gt;
Muchos proyectos tienen este ciclo de vida:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Escribir el código&lt;/li&gt;
&lt;li&gt;Instalar paquetes&lt;/li&gt;
&lt;li&gt;Mandar a un ambiente de CI/CD&lt;/li&gt;
&lt;li&gt;Enviar proyecto a producción&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Los ataques de supply chain se insertan en uno de estos pasos comprometiendo toda la cadena de pasos siguientes.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo se infecta una librería?
&lt;/h2&gt;

&lt;p&gt;Los atacantes no siempre comprometen el paquete popular directamente. Muchas veces infectan una dependencia interna de ese paquete.&lt;/p&gt;

&lt;p&gt;Tu al instalar el paquete popular, sin saberlo estás instalando también el código de la dependencia infectada.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo funcionan los lifecycle scripts en npm?
&lt;/h2&gt;

&lt;p&gt;Los ataques recientes han utilizado una funcionalidad del gestor de paquetes de npm: la capacidad de ejecutar scripts antes o después de la instalación de un paquete.&lt;/p&gt;

&lt;p&gt;A esto se le llaman "lifecycle scripts". Muchos paquetes los usan de manera legítima para preparar pasos previos a la instalación, como la compilación de paquetes nativos. Aunque la documentación de npm recomienda evitarlos, algunos paquetes los necesitan, y es precisamente esa característica la que los paquetes infectados utilizan.&lt;/p&gt;

&lt;p&gt;Como esto es un proceso que sucede antes de que se instale el paquete, nosotros no nos percatamos de lo que se ejecuta. Los paquetes con malware ejecutan todos los pasos que necesitan para infectar tu equipo, robar información y después dejar todo limpio como si nada hubiera pasado. Eso es lo más crítico.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo proteger tu proyecto de paquetes maliciosos en npm?
&lt;/h2&gt;

&lt;p&gt;Hay varias medidas que podemos tomar. Vamos una por una.&lt;/p&gt;
&lt;h3&gt;
  
  
  No actualices versiones a lo loco
&lt;/h3&gt;

&lt;p&gt;Es muy común utilizar herramientas como &lt;a href="https://www.npmjs.com/package/npm-check-updates" rel="noopener noreferrer"&gt;npm-check-updates&lt;/a&gt; para actualizar dependencias automáticamente. Siempre queremos tener lo último y pensamos que eso es lo correcto, pero realmente introducimos un vector de ataque.&lt;/p&gt;

&lt;p&gt;La última versión puede traer malware. Mejor revisa qué se publicó, qué cambió en el changelog y si hay reportes antes de actualizar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bloquea los lifecycle scripts
&lt;/h3&gt;

&lt;p&gt;Como vimos, es por estos scripts que muchos de los ataques suceden. Podemos desactivarlos al instalar una dependencia.&lt;/p&gt;

&lt;p&gt;De manera individual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt; &amp;lt;pkg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De manera global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; ignore-scripts &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O por proyecto con el archivo &lt;code&gt;.npmrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ignore-scripts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto se agregó en la versión v11 de npm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bloquea instalaciones desde Git
&lt;/h3&gt;

&lt;p&gt;Adicional a esto necesitas configurar el flag de &lt;code&gt;allow-git&lt;/code&gt; para evitar que se instalen paquetes desde algún repositorio de Git en vez del registro de npm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt; &lt;span class="nt"&gt;--allow-git&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &amp;lt;pkg&amp;gt;

&lt;span class="c"&gt;# global&lt;/span&gt;
npm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; allow-git none

&lt;span class="c"&gt;# .npmrc&lt;/span&gt;
ignore-scripts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;allow-git&lt;span class="o"&gt;=&lt;/span&gt;none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fija la versión de tus dependencias
&lt;/h3&gt;

&lt;p&gt;Algo que yo particularmente no sabía es que fijar las versiones es una buena práctica. Estamos acostumbrados a instalar con &lt;code&gt;npm install&lt;/code&gt; y asumir que el símbolo &lt;code&gt;^&lt;/code&gt; al inicio de la versión en &lt;code&gt;package.json&lt;/code&gt; está bien.&lt;/p&gt;

&lt;p&gt;Pero ese &lt;code&gt;^&lt;/code&gt; significa que al actualizar puedes descargar cualquier versión del paquete que no haga un salto de major version (el primer número). Es decir, si tienes la versión &lt;code&gt;1.x.x&lt;/code&gt;, npm puede instalar cualquier &lt;code&gt;1.y.z&lt;/code&gt; sin preguntarte.&lt;/p&gt;

&lt;p&gt;Para fijar la versión exacta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt; &amp;lt;pkg&amp;gt;

&lt;span class="c"&gt;# global&lt;/span&gt;
npm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; save-exact &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# .npmrc&lt;/span&gt;
save-exact&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  No instales la versión más reciente
&lt;/h3&gt;

&lt;p&gt;Otra precaución: evita instalar el paquete más reciente que existe. Esto puede pasar cuando haces un &lt;code&gt;npm update&lt;/code&gt; o instalas el paquete por primera vez.&lt;/p&gt;

&lt;p&gt;Muchos de los infectados en los ataques fue porque se publicó una versión nueva y muchas personas la instalaron de inmediato. Al paso de unas horas los contribuidores del paquete se dieron cuenta de que el paquete había sido comprometido.&lt;/p&gt;

&lt;p&gt;Para evitar esto existe &lt;code&gt;min-release-age&lt;/code&gt;: configuras cuánto tiempo debe haber pasado desde que se publicó un paquete para que npm lo instale.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--min-release-age&lt;/span&gt; 3 &amp;lt;pkg&amp;gt;

&lt;span class="c"&gt;# .npmrc&lt;/span&gt;
min-release-age&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="c"&gt;# 3 dias (npm usa días)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta configuración está disponible a partir de la versión v11 de npm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tu &lt;code&gt;.npmrc&lt;/code&gt; defensivo mínimo
&lt;/h3&gt;

&lt;p&gt;Así queda el &lt;code&gt;.npmrc&lt;/code&gt; mínimo para tus proyectos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;save-exact&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;ignore-scripts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;min-release-age&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y en CI, siempre &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt;, nunca &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerar pnpm
&lt;/h2&gt;

&lt;p&gt;pnpm es una alternativa a npm que bloquea los lifecycle scripts por defecto. Personalmente lo estoy usando para mis proyectos porque reduce el consumo de espacio (optimiza los &lt;code&gt;node_modules&lt;/code&gt;) y porque trae estas protecciones incluidas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bloqueo de dependencias y builds
&lt;/h3&gt;

&lt;p&gt;Por defecto, pnpm bloquea los scripts de pre/post instalación. Si algún paquete legítimo los necesita (como &lt;code&gt;esbuild&lt;/code&gt; o &lt;code&gt;next&lt;/code&gt;), puedes permitirlo explícitamente en el &lt;code&gt;pnpm-workspace.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Permitir dependencias que sí pueden usar los lifecycle scripts (pnpm 10+)&lt;/span&gt;
&lt;span class="na"&gt;allowBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;strictDepBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Muestra error si alguna dependencia no listada hace uso de lifecycle scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tiempo de antigüedad
&lt;/h3&gt;

&lt;p&gt;Como en npm, puedes configurar el tiempo mínimo que debe haber pasado para instalar un paquete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;allowBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;strictDepBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;minimumReleaseAge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1440&lt;/span&gt; &lt;span class="c1"&gt;# mínimo 24 hrs (pnpm usa minutos)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Snyk recomienda que usemos al menos 21 días como periodo para instalar una nueva dependencia.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona &lt;code&gt;trustPolicy&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;pnpm asigna un &lt;strong&gt;nivel de confianza&lt;/strong&gt; a cada versión publicada de un paquete, basado en cómo fue publicada. Los niveles de mayor a menor son:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trusted Publisher&lt;/strong&gt;: publicado vía GitHub Actions con OIDC (el CI firma criptográficamente que el paquete viene de un workflow específico en un repo específico)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance&lt;/strong&gt;: tiene una prueba verificable de npm que confirma dónde y cómo se construyó el paquete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signatures&lt;/strong&gt;: tiene firma del registry de npm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sin evidencia&lt;/strong&gt;: publicado sin ninguna señal de confianza&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si configuras &lt;code&gt;trustPolicy: no-downgrade&lt;/code&gt;, pnpm compara el nivel de confianza de la versión que vas a instalar con el de versiones anteriores del mismo paquete. Si la confianza baja (por ejemplo, un paquete que siempre se publicó desde CI de repente aparece publicado sin ninguna evidencia), pnpm aborta la instalación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revisar antes de instalar
&lt;/h2&gt;

&lt;p&gt;No instales paquetes de manera ciega. Existen herramientas que te ayudan a revisarlos antes.&lt;/p&gt;

&lt;h3&gt;
  
  
  npq
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lirantal/npq" rel="noopener noreferrer"&gt;npq&lt;/a&gt; te ayuda a revisar lo que piensas instalar antes de siquiera instalarlo. Te advierte de posibles vulnerabilidades.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx npq &lt;span class="nb"&gt;install &lt;/span&gt;express &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir de lo que veas puedes decidir si instalas la última versión o te esperas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Socket Firewall
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://socket.dev/blog/introducing-socket-firewall" rel="noopener noreferrer"&gt;Socket Firewall&lt;/a&gt; es similar a npq pero además te permite usarlo con el manejador de paquetes de Python (uv). Personalmente no lo he utilizado, pero lo mencionan en las buenas prácticas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Medidas adicionales
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Evitar el uso de .env con información sensible
&lt;/h3&gt;

&lt;p&gt;No tengas tus claves de producción, tokens o lo que sea importante en tu &lt;code&gt;.env&lt;/code&gt; de manera plana como solíamos hacerlo. Si bien no subimos esta información a GitHub, en los ataques de supply chain los paquetes maliciosos tienen acceso al entorno donde se ejecutan. Esto quiere decir: tus accesos están expuestos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nodejs-security.com/blog/do-not-use-secrets-in-environment-variables-and-here-is-how-to-do-it-better" rel="noopener noreferrer"&gt;Una alternativa es usar secretos. En su blog, Liran te explica cómo hacerlo.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Usa devcontainers
&lt;/h3&gt;

&lt;p&gt;Personalmente ya sabía que existían pero no suelo trabajar con ellos. En las &lt;a href="https://github.com/lirantal/npm-security-best-practices?tab=readme-ov-file#8-work-in-dev-containers" rel="noopener noreferrer"&gt;buenas prácticas de seguridad de Node.js mencionan&lt;/a&gt; la opción de usarlos para aislar los ataques y reducir el área de ataque a únicamente ese contenedor.&lt;/p&gt;

&lt;p&gt;Si te gustaría un tutorial, déjame un comentario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifica tu ambiente
&lt;/h3&gt;

&lt;p&gt;Para verificar si tu ambiente ya bloquea los pre/post scripts puedes probar &lt;a href="https://www.npmjs.com/package/@lavamoat/preinstall-always-fail" rel="noopener noreferrer"&gt;este paquete creado específicamente para eso&lt;/a&gt;. Si la instalación falla, significa que tus protecciones están funcionando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  npm &lt;span class="nb"&gt;install&lt;/span&gt; @lavamoat/preinstall-always-fail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No estamos 100% seguros
&lt;/h2&gt;

&lt;p&gt;Con estas prácticas reducimos el área de ataque, pero lo importante es mantenernos atentos a las noticias de seguridad y reducir el número de paquetes instalados si es posible.&lt;/p&gt;

&lt;p&gt;Entre menos paquetes tengas, menos área de ataque y menos dependencias que vigilar. JavaScript ha evolucionado tanto que muchas cosas que antes necesitaban una librería hoy son triviales de hacer de forma nativa, o la librería estándar de Node.js ya las incluye.&lt;/p&gt;

&lt;p&gt;Con un &lt;code&gt;.npmrc&lt;/code&gt; bien configurado ya reduces la mayoría de los vectores de ataque. Recuerda revisar tus paquetes con npq o algún otra herramienta antes de instalarlos.&lt;/p&gt;

&lt;p&gt;¿Ya tenías alguna de estas configuraciones? ¿Usas alguna otra medida? ¿Hay algo que no sea correcto? Deja tus comentarios.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: no soy experto en seguridad. Esto es información recopilada para mi propio uso y para ayudar a los demás.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>security</category>
      <category>npm</category>
      <category>node</category>
    </item>
  </channel>
</rss>
