Patrones de EDA + POO + práctica
Dos punteros, sumas de prefijos y diseño limpio
Por qué importa
Los patrones más la estructura convierten la programación al azar en una resolución de problemas confiable.
La idea
La mayoría de las preguntas de entrevista son un puñado de patrones: dos punteros, ventana deslizante, suma de prefijos, BFS/DFS, conteo con tablas hash, búsqueda binaria. Reconoce el patrón y luego aplica la plantilla.
Pruébalo
Dos punteros: suma de pares en un arreglo ordenado:
def two_sum_sorted(nums, target):
l, r = 0, len(nums) - 1
while l < r:
s = nums[l] + nums[r]
if s == target:
return (l, r)
if s < target:
l += 1
else:
r -= 1
return None
print(two_sum_sorted([1, 2, 4, 7, 11, 15], 13))
print(two_sum_sorted([1, 2, 4, 7, 11, 15], 99))
Sumas de prefijos: responde "la suma de cualquier rango" en O(1) tras un preprocesamiento O(n):
nums = [2, 4, 5, 1, 9, 3, 7]
prefix = [0]
for x in nums: prefix.append(prefix[-1] + x)
def range_sum(l, r):
# inclusive l, exclusive r
return prefix[r] - prefix[l]
print(range_sum(1, 4)) # 4 + 5 + 1 = 10
print(range_sum(0, len(nums))) # all
POO: una pequeña pila (Stack) con anotaciones de tipo:
class Stack:
def __init__(self):
self._data: list = []
def push(self, x):
self._data.append(x)
def pop(self):
if not self._data: raise IndexError("pop from empty stack")
return self._data.pop()
def peek(self):
return self._data[-1] if self._data else None
def __len__(self):
return len(self._data)
def __repr__(self):
return f"Stack({self._data!r})"
s = Stack()
for x in [1, 2, 3]: s.push(x)
print(s, "len:", len(s))
print("pop:", s.pop())
print("peek:", s.peek())
Plantillas de patrones
Memoriza los esqueletos; el problema solo rellena la condición.
Ventana deslizante
l = 0
for r in range(len(arr)):
# expand window with r
# shrink from the left when the condition fails
if condition:
l += 1
Patrón de pila
stack = []
for ch in s:
if stack and ch == stack[-1]:
stack.pop()
else:
stack.append(ch)
Conceptos básicos de POO
class Player:
def __init__(self, name):
self.name = name
self.score = 0
def add(self, points):
self.score += points
- Una clase define un molde.
- Una instancia es un objeto concreto.
selfse refiere al objeto actual.
Chuleta de patrones de EDA
| Patrón | Cuándo recurrir a él | | --- | --- | | Dos punteros | Arreglos ordenados, par desde los extremos | | Ventana deslizante | Subarreglo con una suma / condición | | Sumas de prefijos | Consultas de suma por rango | | Tabla hash (dict) | Contar frecuencias, buscar el complemento | | Pila | Paréntesis válidos, pila monótona |
Si ves X, piensa en Y
- "Elementos únicos" →
set - "Contar frecuencia" →
dict - "Buscar el complemento / algo visto antes" →
dict - "Invertir / palíndromo / par desde los extremos" → dos punteros
- "Total acumulado" → suma de prefijos
Funciones integradas que debes memorizar
len, type, range, enumerate, sorted, sum, min, max
Sistema de práctica
Diario de errores
Usa este formato cada vez que te atasques; la meta es extraer una regla reutilizable de cada error:
- Fecha:
- Problema:
- Lo que esperaba:
- Lo que ocurrió:
- Causa raíz:
- Solución:
- Regla para la próxima vez:
Ejemplo de causa raíz: usé b = a en lugar de a.copy().
Seguimiento de LeetCode (muestra)
| # | Problema | Tema | Estado | Idea clave | Error | Reintento | | - | ------- | ----- | ------ | -------- | ------- | ----- | | 1 | Two Sum | dict | | búsqueda del complemento | | | | 2 | Valid Palindrome | strings | | normalizar + dos punteros | | | | 3 | Contains Duplicate | set | | comparar la longitud del conjunto | | | | 4 | Valid Anagram | dict | | conteos de frecuencia | | | | 5 | Running Sum | lists | | total acumulado de prefijos | | |
Verificación rápida
- P: ¿Cuándo deberías usar una clase? R: Cuando el estado y el comportamiento van juntos.
Mini ejercicios
- Implementa una inversión con dos punteros.
- Escribe una clase pequeña con dos métodos.
Buenas y malas prácticas
- Escribe plantillas pequeñas que puedas reutilizar.
- Mantén las clases simples y enfocadas.
- No sobre-diseñes cuando basta con una función.
Errores comunes
- Error: Olvidar actualizar los punteros en los bucles. Solución: Mueve siempre al menos un puntero.
- Error: Abusar de las clases para datos simples. Solución: Empieza con funciones y refactoriza más tarde.
Conclusiones clave
- Dos punteros: arreglo ordenado, encontrar un par / partición.
- Ventana deslizante: subarreglo contiguo con una restricción (el más largo, el más pequeño).
- Suma de prefijos: muchas consultas de suma por rango sobre un arreglo fijo.
- POO: encapsula el ESTADO; el comportamiento le sigue. Usa
__repr__para que depurar sea indoloro. - Lleva un diario de errores y un seguimiento de problemas: registrar los errores es como mejoras más rápido.