Fundamentos de arrays y operaciones in-place
Repase la indexación y la mutación, así como los errores más habituales en entrevistas sobre arrays, como los desfases de uno y modificar una lista mientras se itera.
Fundamentos de arrays y operaciones in-place es una lección gratuita de DSA Interview Prep en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de DSA Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de DSA Interview Prep incluye 4 lecciones en total.
Los arrays como memoria contigua
Internamente, una lista de Python se basa en un array dinámico: un bloque contiguo de memoria en el que los elementos se almacenan en direcciones consecutivas. Esta disposición proporciona un acceso aleatorio O(1) mediante el índice: Python calcula address = base + index × element_size al instante. Las inserciones o eliminaciones en el centro requieren desplazar todos los elementos posteriores, con un coste de O(n). Esta asimetría origina la mayoría de los debates sobre los equilibrios de los arrays en las entrevistas.
nums = [10, 20, 30, 40, 50]
# O(1) random access
print(nums[2]) # 30
print(nums[-1]) # 50
# O(1) append (amortised)
nums.append(60)
print(nums) # [10,20,30,40,50,60]
# O(n) insert at beginning
nums.insert(0, 0) # shifts all elements right
print(nums) # [0,10,20,30,40,50,60]Desfase de uno: el error clásico de los arrays
Los errores de desfase de uno son la fuente más frecuente de respuestas incorrectas en los problemas con arrays. La indexación basada en cero de Python significa que el último índice válido es len(arr) - 1. Al escribir bucles, decida si necesita < o <= comprobando la condición límite con la entrada válida más pequeña (n=1 o n=2). Antes de enviar la solución, compruebe siempre el límite con ejemplos concretos.
def find_max(nums):
# Use len(nums)-1 as last index
max_val = nums[0] # safe if n >= 1
for i in range(1, len(nums)): # start at 1, not 0
if nums[i] > max_val:
max_val = nums[i]
return max_val
print(find_max([3, 1, 4, 1, 5])) # 5
print(find_max([7])) # 7 (single element)
# Would crash if we accessed nums[len(nums)]Inversión in situ con dos punteros
Invertir un array in situ utiliza dos punteros que comienzan en extremos opuestos y avanzan hacia el centro intercambiando elementos hasta encontrarse. Esto requiere un espacio adicional O(1) y un tiempo O(n). La condición left < right (estrictamente menor) garantiza la corrección tanto para longitudes pares como impares: con un número impar de elementos, el elemento central permanece automáticamente en su lugar.
def reverse_inplace(arr):
left, right = 0, len(arr) - 1
while left < right:
arr[left], arr[right] = arr[right], arr[left]
left += 1
right -= 1
# Space: O(1) Time: O(n)
a = [1, 2, 3, 4, 5]
reverse_inplace(a)
print(a) # [5, 4, 3, 2, 1]
b = [1, 2, 3]
reverse_inplace(b)
print(b) # [3, 2, 1] middle element unchangedRotar un array in situ
Para rotar un array k posiciones hacia la derecha, puede hacerlo in situ invirtiendo tres segmentos: invierta el array completo, después los primeros k elementos y, por último, los n-k elementos restantes. Esto consigue un tiempo O(n) y un espacio O(1), mucho mejor que el enfoque de O(n) de espacio que utiliza slicing y concatenación. Reduzca siempre k módulo n para gestionar k ≥ n.
def rotate(nums, k):
n = len(nums)
k %= n # handle k >= n
def rev(l, r):
while l < r:
nums[l], nums[r] = nums[r], nums[l]
l += 1; r -= 1
rev(0, n-1) # reverse all
rev(0, k-1) # reverse first k
rev(k, n-1) # reverse rest
a = [1, 2, 3, 4, 5, 6, 7]
rotate(a, 3)
print(a) # [5, 6, 7, 1, 2, 3, 4]Eliminar elementos in situ
Eliminar duplicados o valores objetivo in situ utiliza un puntero de escritura que indica dónde debe escribirse el siguiente elemento válido. El puntero de lectura avanza; cuando encuentra un elemento válido, lo copia en la posición de escritura y avanza ambos punteros. Este es el patrón fundamental de problemas de LeetCode como 'remove element', 'remove duplicates from sorted array' y 'move zeroes'.
def remove_element(nums, val):
write = 0
for read in range(len(nums)):
if nums[read] != val:
nums[write] = nums[read]
write += 1
return write # new length
nums = [3, 2, 2, 3]
new_len = remove_element(nums, 3)
print(nums[:new_len]) # [2, 2]
nums2 = [0, 1, 2, 2, 3, 0, 4, 2]
new_len2 = remove_element(nums2, 2)
print(nums2[:new_len2]) # [0, 1, 3, 0, 4]Mover los ceros: puntero de lectura y escritura
Mueva todos los ceros al final de un array y conserve el orden de los elementos distintos de cero. El enfoque del puntero de lectura y escritura coloca cada elemento distinto de cero en la posición de escritura y luego rellena con ceros el tramo final. Un enfoque alternativo intercambia los ceros hacia atrás y conserva el orden sin una segunda pasada de relleno. Ambos enfoques tienen una complejidad temporal de O(n) y espacial de O(1).
def move_zeroes(nums):
write = 0
# Move all non-zeroes to front
for read in range(len(nums)):
if nums[read] != 0:
nums[write] = nums[read]
write += 1
# Fill rest with zeroes
while write < len(nums):
nums[write] = 0
write += 1
a = [0, 1, 0, 3, 12]
move_zeroes(a)
print(a) # [1, 3, 12, 0, 0]Elevar al cuadrado y ordenar in situ
Dado un array ordenado de enteros que puede contener valores negativos, devuelva un array con sus cuadrados en orden. El enfoque ingenuo eleva los valores al cuadrado y luego los ordena: O(n log n). El enfoque óptimo de dos punteros aprovecha que los cuadrados mayores proceden de cualquiera de los extremos de la entrada ordenada: compare los valores absolutos de los elementos de los extremos izquierdo y derecho y rellene el resultado de derecha a izquierda en O(n).
def sorted_squares(nums):
n = len(nums)
result = [0] * n
left, right = 0, n - 1
pos = n - 1 # fill from the right
while left <= right:
l_sq = nums[left] ** 2
r_sq = nums[right] ** 2
if l_sq > r_sq:
result[pos] = l_sq
left += 1
else:
result[pos] = r_sq
right -= 1
pos -= 1
return result
print(sorted_squares([-4, -1, 0, 3, 10]))
# [0, 1, 9, 16, 100]Encontrar el pivote y particionar
El problema de la bandera nacional neerlandesa particiona un array en tres secciones (menores que el pivote, iguales al pivote y mayores que el pivote) in situ mediante tres punteros. Este es el subpaso clave de quicksort y la solución al problema de LeetCode 'sort colors'. Mantener la invariante de que los elementos anteriores al puntero low son < pivot y los posteriores al puntero high son > pivot guía el algoritmo.
def sort_colors(nums):
# Dutch national flag: 0s, 1s, 2s
low, mid, high = 0, 0, len(nums) - 1
while mid <= high:
if nums[mid] == 0:
nums[low], nums[mid] = nums[mid], nums[low]
low += 1; mid += 1
elif nums[mid] == 1:
mid += 1
else:
nums[mid], nums[high] = nums[high], nums[mid]
high -= 1 # don't advance mid: new nums[mid] unexamined
a = [2, 0, 2, 1, 1, 0]
sort_colors(a)
print(a) # [0, 0, 1, 1, 2, 2]Modificar elementos de un array durante la iteración
Puede modificar los valores de los elementos de forma segura (por ejemplo, multiplicarlos por -1 para marcar los que ya ha visitado) mientras itera, pero no cambie nunca la longitud de una lista durante un bucle for. Un truco de codificación seguro consiste en codificar temporalmente dos valores en un solo entero (por ejemplo, mediante el bit de signo) para simular un booleano adicional por elemento sin asignar espacio extra. Esto aparece en problemas como 'encontrar todos los números que desaparecieron en un array'.
def find_disappeared(nums):
# Mark visited by negating the value at the index
for n in nums:
idx = abs(n) - 1
if nums[idx] > 0:
nums[idx] *= -1 # mark as seen
# Indices with positive values are missing
return [i + 1 for i, v in enumerate(nums) if v > 0]
print(find_disappeared([4, 3, 2, 7, 8, 2, 3, 1]))
# [5, 6] -- O(n) time, O(1) extra spaceLista de comprobación de patrones de entrevistas sobre arrays
Antes de programar cualquier problema de arrays, repase esta lista mental:
- ¿Está ordenado el array? (permite usar dos punteros y búsqueda binaria)
- ¿Los elementos están dentro de un rango acotado (p. ej., 1..n)? (permite usar trucos basados en índices)
- ¿Es necesario hacerlo in situ? (puntero de lectura y escritura o intercambios)
- ¿Necesita todos los pares o solo uno? (determina si los bucles anidados son aceptables)
- Casos límite: array vacío, un solo elemento, todos los valores iguales
def max_profit(prices):
# Pattern: single scan, track running minimum
# Time: O(n), Space: O(1)
if not prices: return 0 # edge case: empty
min_price = prices[0]
max_prof = 0
for price in prices[1:]: # start at index 1
max_prof = max(max_prof, price - min_price)
min_price = min(min_price, price)
return max_prof
print(max_profit([7, 1, 5, 3, 6, 4])) # 5
print(max_profit([7, 6, 4, 3, 1])) # 0Algoritmo de Kadane: subarray de suma máxima
El algoritmo de Kadane encuentra el subarray contiguo de suma máxima en O(n) y con espacio O(1). En cada paso, decida si debe ampliar el subarray actual o comenzar uno nuevo: current = max(num, current + num). Si current + num es menor que num por sí solo, el subarray actual nos está perjudicando y empezamos de nuevo. Mantenga el máximo global durante todo el recorrido.
def max_subarray(nums):
current = global_max = nums[0]
for n in nums[1:]:
current = max(n, current + n) # extend or restart
global_max = max(global_max, current)
return global_max
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))
# 6 (subarray [4, -1, 2, 1])
print(max_subarray([-1, -2, -3]))
# -1 (all negative: take the least negative)Comprobación rápida
Ponga a prueba su comprensión de los conceptos de Data Structures & Algorithms — Coding Interview Prep de esta lección.
Resumen de la lección
En esta lección ha aprendido: los arrays ofrecen acceso aleatorio en O(1), pero las inserciones y eliminaciones en el medio cuestan O(n); conocer esta asimetría orienta la elección del algoritmo, el patrón del puntero de lectura y escritura permite eliminar elementos o mover valores in situ en O(n) y con O(1) de espacio, y la codificación con el bit de signo y los trucos que usan el índice como marca permiten resolver en O(1) de espacio problemas que, de otro modo, requerirían un array auxiliar. A continuación exploraremos las sumas de prefijos y los totales acumulados.
Preguntas frecuentes
¿La lección «Fundamentos de arrays y operaciones in-place» es gratis?
Sí — el texto completo de «Fundamentos de arrays y operaciones in-place» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de DSA Interview Prep, actualiza a CoddyKit PRO. El curso de DSA Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «Fundamentos de arrays y operaciones in-place»?
Repase la indexación y la mutación, así como los errores más habituales en entrevistas sobre arrays, como los desfases de uno y modificar una lista mientras se itera. Practicas DSA Interview Prep con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar DSA Interview Prep?
No se requiere experiencia previa. DSA Interview Prep en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Fundamentos de arrays y operaciones in-place»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de DSA Interview Prep?
Sí. Cada lección de DSA Interview Prep incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Fundamentos de arrays y operaciones in-place
- Sumas de prefijos y totales acumulados
- Dos punteros: extremos opuestos
- Dos punteros: lento y rápido