Entrevista simulada cronometrada: problemas fáciles y medios
Resuelva tres problemas en un tiempo límite de 45 minutos, verbalice su proceso de razonamiento como lo haría en una entrevista real y revise después las soluciones óptimas.
Entrevista simulada cronometrada: problemas fáciles y medios es una lección gratuita de Coding Interview Prep en CoddyKit. Esta es la lección 2 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 Coding Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Coding Interview Prep incluye 4 lecciones en total.
Cómo utilizar esta entrevista simulada
Esta lección simula una sesión real de entrevista de programación. Para cada problema, debe: (1) leerlo una vez, (2) identificar el patrón en menos de 60 segundos, (3) explicar su enfoque y su complejidad, (4) escribir la solución y (5) probarla con ejemplos. Configure un temporizador. Un problema fácil debería llevarle entre 10 y 15 minutos; uno de dificultad media, entre 20 y 25 minutos.
No consulte la solución por adelantado: eso anula el propósito del ejercicio. Si se atasca después de 5 minutos, vuelva a leer el enunciado y busque la palabra clave que revela el patrón (¿ordenado?, ¿mínimo?, ¿todas las combinaciones?, ¿subarray?). La capacidad de desbloquearse por sí mismo es tan importante como la capacidad de resolver problemas rápidamente.
# Mock interview timer simulation
import time
class InterviewTimer:
def __init__(self, total_minutes):
self.total = total_minutes * 60
self.start = None
def begin(self, problem_name):
self.start = time.time()
print(f'TIMER STARTED: {problem_name}')
print(f'You have {self.total//60} minutes. Go!')
def checkpoint(self, label):
if self.start:
elapsed = time.time() - self.start
remaining = self.total - elapsed
print(f'[{label}] Elapsed: {elapsed:.0f}s, Remaining: {remaining:.0f}s')
# Usage in real practice:
timer = InterviewTimer(15) # 15-minute easy problem
timer.begin('Two Sum')
time.sleep(1)
timer.checkpoint('Identified pattern')Problema fácil 1: paréntesis válidos
Problema: Dada una cadena que contiene únicamente '(', ')', '{', '}', '[' y ']', determine si la cadena de entrada es válida. Una cadena es válida si cada corchete de apertura se cierra con un corchete del mismo tipo y en el orden correcto.
Señal: Los pares deben coincidir, el orden importa y el corchete de apertura más reciente debe cerrarse primero → Pila. Introduzca los corchetes de apertura en la pila; extraiga uno y verifíquelo al encontrar un corchete de cierre. Si la pila está vacía cuando se intenta extraer un elemento o contiene elementos sobrantes al final, la cadena no es válida. Tiempo O(n), espacio O(n).
def is_valid(s):
stack = []
matching = {')': '(', '}': '{', ']': '['}
for char in s:
if char in '({[':
stack.append(char)
else:
if not stack or stack[-1] != matching[char]:
return False
stack.pop()
return len(stack) == 0
# Test cases
test_cases = [
('()', True),
('()[]{}' , True),
('(]', False),
('([)]', False),
('{[]}', True),
('', True), # empty string is valid
('(((', False), # unmatched opens
(')]', False), # close without open
]
for s, expected in test_cases:
result = is_valid(s)
status = 'PASS' if result == expected else 'FAIL'
print(f'{status}: is_valid({repr(s)}) = {result} (expected {expected})')Problema fácil 2: mejor momento para comprar y vender acciones
Problema: Dado un array prices donde prices[i] es el precio de la acción el día i, encuentre el beneficio máximo de una compra y una venta (debe comprar antes de vender). Devuelva 0 si no es posible obtener beneficios.
Señal: Diferencia máxima en la que la posición izquierda debe preceder a la derecha → Mantenga el mínimo acumulado mientras recorre el array de izquierda a derecha. Cada día, el beneficio potencial es current_price - min_so_far. Actualice el beneficio máximo. Esto es O(n)/O(1) y constituye un caso especial del algoritmo de Kadane.
def max_profit(prices):
if not prices:
return 0
min_price = float('inf')
max_profit = 0
for price in prices:
if price < min_price:
min_price = price
elif price - min_price > max_profit:
max_profit = price - min_price
return max_profit
# Test cases
test_cases = [
([7, 1, 5, 3, 6, 4], 5), # buy at 1, sell at 6
([7, 6, 4, 3, 1], 0), # monotonically decreasing: no profit
([2, 4, 1], 2), # buy at 2, sell at 4
([1], 0), # single price: no transaction possible
([3, 3, 3], 0), # flat: no profit
]
for prices, expected in test_cases:
result = max_profit(prices)
status = 'PASS' if result == expected else 'FAIL'
print(f'{status}: max_profit({prices}) = {result} (expected {expected})')Problema medio 1: suma de tres
Problema: Dado un array, encuentre todas las tripletas únicas cuya suma sea cero. La solución no debe contener tripletas duplicadas.
Patrón: Dos punteros extendidos a tres elementos. Ordene el array. Para cada elemento nums[i], utilice dos punteros left = i+1 y right = n-1 para encontrar pares cuya suma sea -nums[i]. Omita los duplicados avanzando más allá de los valores idénticos. Tiempo O(n²), espacio O(1) sin contar la salida. La ordenación simplifica el tratamiento de los duplicados.
def three_sum(nums):
nums.sort()
result = []
n = len(nums)
for i in range(n - 2):
# Skip duplicate values for the first element
if i > 0 and nums[i] == nums[i - 1]:
continue
left, right = i + 1, n - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total == 0:
result.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1 # skip duplicate lefts
while left < right and nums[right] == nums[right - 1]:
right -= 1 # skip duplicate rights
left += 1; right -= 1
elif total < 0:
left += 1
else:
right -= 1
return result
print(three_sum([-1, 0, 1, 2, -1, -4])) # [[-1,-1,2],[-1,0,1]]
print(three_sum([0, 0, 0, 0])) # [[0,0,0]]
print(three_sum([])) # []
print(three_sum([1, 2, -2, -1])) # []Problema de nivel medio 2: Subcadena más larga sin caracteres repetidos
Problema: Dada una cadena, encuentre la longitud de la subcadena más larga sin caracteres repetidos.
Patrón: Ventana deslizante con un conjunto (o un diccionario de las últimas posiciones). Mantenga una ventana [left, right]. Amplíe right incluyendo cada carácter. Si un carácter se repite (ya está en la ventana), reduzca desde la izquierda hasta eliminar el duplicado. Registre el tamaño máximo de ventana observado. Tiempo O(n), espacio O(min(n, alphabet_size)).
def length_of_longest_substring(s):
char_index = {} # character -> last seen index
left = 0
max_len = 0
for right, char in enumerate(s):
if char in char_index and char_index[char] >= left:
left = char_index[char] + 1 # shrink window past duplicate
char_index[char] = right
max_len = max(max_len, right - left + 1)
return max_len
# Test cases
test_cases = [
('abcabcbb', 3), # 'abc'
('bbbbb', 1), # 'b'
('pwwkew', 3), # 'wke'
('', 0), # empty string
('au', 2), # full string
('dvdf', 3), # 'vdf' (skip the first d)
]
for s, expected in test_cases:
result = length_of_longest_substring(s)
status = 'PASS' if result == expected else 'FAIL'
print(f'{status}: len_longest({repr(s)}) = {result} (expected {expected})')Problema de nivel medio 3: Cambio de monedas
Problema: Dadas las denominaciones de varias monedas y una cantidad objetivo, encuentre el número mínimo de monedas necesario para alcanzar dicha cantidad. Devuelva -1 si es imposible.
Patrón: DP clásica unidimensional (variante del problema de la mochila ilimitada). dp[i] = número mínimo de monedas para la cantidad i. Inicialice dp[0] = 0 y todos los demás valores con infinito. Para cada cantidad de 1 a target, pruebe todas las denominaciones de monedas. dp[i] = min(dp[i], dp[i - coin] + 1) para cada moneda válida. Tiempo O(amount × len(coins)), espacio O(amount).
def coin_change(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0 # 0 coins to make amount 0
for i in range(1, amount + 1):
for coin in coins:
if coin <= i and dp[i - coin] + 1 < dp[i]:
dp[i] = dp[i - coin] + 1
return dp[amount] if dp[amount] != float('inf') else -1
# Test cases
test_cases = [
([1, 5, 11], 15, 3), # 11+1+1+1+1... wait: 11+1+1+1+1=5 coins? No: 5+5+5=3
([2], 3, -1), # impossible (only even coins)
([1], 0, 0), # 0 coins for amount 0
([1, 2, 5], 11, 3), # 5+5+1
([186, 419, 83, 408], 6249, 20), # stress test
]
for coins, amount, expected in test_cases:
result = coin_change(coins, amount)
status = 'PASS' if result == expected else 'FAIL'
print(f'{status}: coin_change({coins}, {amount}) = {result} (expected {expected})')Flujo de trabajo para resolver problemas bajo presión de tiempo
Cuando se esté acabando el tiempo, priorice en este orden: (1) una solución de fuerza bruta funcional con una salida correcta antes que una solución óptima incompleta, (2) abordar los casos límite de forma visible, (3) escribir código limpio y legible en lugar de expresiones ingeniosas de una sola línea. Los entrevistadores prefieren una solución limpia O(n²) que supere todos los casos de prueba a una solución O(n) con un error sutil.
Si se da cuenta de que su solución O(n²) es incorrecta, no la abandone a mitad de camino: termínela, pruébela y, después, ofrézcase a optimizarla si queda tiempo. Una solución óptima a medio escribir obtiene menos reconocimiento que una solución completa, aunque sea subóptima.
# Priority order when time runs out
priority = [
('First priority', 'Correct brute-force that passes all test cases'),
('Second priority', 'Optimal solution with bugs is WORSE than suboptimal correct'),
('Third priority', 'Edge cases handled visibly (empty input, single element, negatives)'),
('Fourth priority', 'Clean variable names and readable code'),
('Fifth priority', 'Add complexity statement as a comment at the top'),
]
print('Under time pressure, prioritise:')
for priority_level, desc in priority:
print(f' {priority_level}: {desc}')
# Adding complexity as a comment
def two_sum_commented(nums, target):
# Time: O(n), Space: O(n)
seen = {}
for i, n in enumerate(nums):
complement = target - n
if complement in seen:
return [seen[complement], i]
seen[n] = i
return []Revisión de su solución: cinco preguntas
Antes de decir «He terminado», hágase estas cinco preguntas:
- ¿Maneja entradas vacías?
[],'',None, n=0 - ¿Maneja un solo elemento? Arrays de tamaño 1, árboles con un nodo
- ¿Maneja elementos todos iguales?
[5, 5, 5, 5],'aaaa' - ¿Maneja los valores mínimos y máximos? Números negativos, enteros muy grandes, 0
- ¿Ha indicado la complejidad temporal y espacial? Big-O con una breve justificación
Estas cinco comprobaciones detectan la mayoría de los errores en las soluciones de entrevistas. Los entrevistadores esperan que los candidatos prueben sus propias soluciones; no le dirán que hay un error a menos que solicite comentarios.
# The five edge-case categories with examples
edge_cases = {
'Empty input': ['[] empty array', '"" empty string', 'None / null'],
'Single element': ['[42]', 'single node tree', 'n=1'],
'All same': ['[3,3,3,3]', '"aaaa"', 'uniform grid'],
'Extreme values': ['[-10^9, 10^9]', 'INT_MAX + 1 overflow check', '0 as input'],
'Already sorted': ['ascending + descending', 'already optimal input'],
}
for category, examples in edge_cases.items():
print(f'{category}:')
for ex in examples:
print(f' - {ex}')
print()
# Template for self-testing:
def test_my_solution(fn, test_cases):
for inputs, expected in test_cases:
result = fn(*inputs) if isinstance(inputs, tuple) else fn(inputs)
status = 'PASS' if result == expected else 'FAIL'
print(f'{status}: {inputs} => {result} (expected {expected})')Cómo abordar las preguntas de seguimiento
Después de resolver el problema, los entrevistadores suelen hacer preguntas de seguimiento. Estos son algunos tipos habituales:
- «¿Puede hacerlo usando O(1) de espacio?» → Busque una modificación in-place o trucos matemáticos
- «¿Qué ocurriría si n fuera muy grande?» → Analice enfoques de procesamiento en streaming, paginación o muestreo
- «¿Qué ocurriría si el array ya estuviera ordenado?» → A menudo existe un algoritmo más sencillo
- «¿Puede paralelizarlo?» → Identifique los subproblemas independientes y analice MapReduce o el paralelismo de tareas
Las preguntas de seguimiento evalúan sus conocimientos profundos y su capacidad de adaptación. Diga «Permítame pensarlo un momento» en lugar de adivinar de inmediato. Una pausa reflexiva es mejor que una respuesta incorrecta expresada con seguridad.
# Follow-up answers for classic problems
follow_ups = [
{
'problem': 'Find duplicate in array 1..n (space O(n) solution uses set)',
'follow_up': 'Can you do it in O(1) space without modifying input?',
'answer': 'Floyd cycle detection: treat array as linked list (slow/fast pointer)',
},
{
'problem': 'Reverse a string (space O(n) with new array)',
'follow_up': 'Can you do it in-place?',
'answer': 'Two pointers from both ends, swap until they meet: O(n) time O(1) space',
},
{
'problem': 'Find max in array: O(n) single pass',
'follow_up': 'What if the array is streamed one element at a time?',
'answer': 'Same algorithm works! Running maximum handles infinite streams',
},
{
'problem': 'Merge sorted arrays O(n+m)',
'follow_up': 'What if you have K sorted arrays?',
'answer': 'Use a min-heap of (value, array_idx, element_idx): O(n log k)',
},
]
for fu in follow_ups:
print(f'Problem: {fu["problem"]}')
print(f'Follow-up: {fu["follow_up"]}')
print(f'Answer: {fu["answer"]}\n')Problema de práctica: agrupar anagramas
Problema: Dado un array de cadenas, agrupe los anagramas. Devuelva una lista de grupos.
Patrón: Mapa de frecuencias como clave. Para cada cadena, ordene sus caracteres (o calcule una tupla de frecuencias de caracteres) como clave canónica. Agrupe las cadenas según esta clave mediante un mapa hash de listas. Tiempo O(n × m log m), donde m es la longitud máxima de una cadena, espacio O(n × m). No se necesitan bucles anidados: basta con recorrer el array una vez.
from collections import defaultdict
def group_anagrams(strs):
# Method 1: sort each string as key
groups = defaultdict(list)
for s in strs:
key = ''.join(sorted(s)) # canonical form
groups[key].append(s)
return list(groups.values())
def group_anagrams_v2(strs):
# Method 2: character count tuple as key (avoids sorting)
groups = defaultdict(list)
for s in strs:
count = [0] * 26
for c in s:
count[ord(c) - ord('a')] += 1
key = tuple(count) # immutable, hashable
groups[key].append(s)
return list(groups.values())
test = ['eat', 'tea', 'tan', 'ate', 'nat', 'bat']
result = [sorted(g) for g in group_anagrams(test)]
result.sort()
print('Groups:', result)
# [['ate','eat','tea'], ['bat'], ['nat','tan']]
print('V2:', [sorted(g) for g in sorted(group_anagrams_v2(test), key=len)])Autoevaluación después de una simulación
Después de cada entrevista simulada, evalúese en estas dimensiones:
- Rapidez para reconocer patrones: ¿Identificó el patrón en <60 segundos?
- Corrección del código: ¿Su primera solución superó todos los casos de prueba?
- Manejo de casos límite: ¿Probó entradas vacías, unitarias y extremas?
- Comunicación: ¿Explicó su razonamiento durante todo el proceso?
- Comprensión de la complejidad: ¿Indicó la complejidad temporal y espacial?
- Recuperación: Si se atascó, ¿cambió de estrategia con naturalidad o se bloqueó?
Califíquese del 1 al 5 en cada dimensión. Dedique la próxima semana de práctica a la dimensión con la calificación más baja. La mayoría de los candidatos necesita mejorar el reconocimiento de patrones o la comunicación, rara vez ambas cosas.
# Self-assessment scoring template
def self_assess(pattern_speed, code_correctness, edge_cases,
communication, complexity, recovery):
scores = {
'Pattern recognition (< 60s)': pattern_speed,
'Code correctness (all tests pass)': code_correctness,
'Edge case handling': edge_cases,
'Communication (thinking aloud)': communication,
'Complexity stated correctly': complexity,
'Recovery when stuck': recovery,
}
total = sum(scores.values())
max_total = len(scores) * 5
print('Self-Assessment Results:')
print('-'*50)
for dim, score in scores.items():
bar = '#' * score + '-' * (5 - score)
print(f'{dim:45s} [{bar}] {score}/5')
print(f'\nTotal: {total}/{max_total} ({total/max_total*100:.0f}%)')
weak = min(scores, key=scores.get)
print(f'Focus area: {weak}')
self_assess(4, 3, 4, 3, 5, 2) # example scoresComprobación rápida
Compruebe 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: abordar los problemas con un flujo de trabajo fijo: leer, identificar el patrón en 60 segundos, indicar la complejidad, programar y después probar con cinco categorías de casos límite, una solución de fuerza bruta funcional es mejor que una solución óptima incompleta cuando se está acabando el tiempo y la autoevaluación después de cada sesión de práctica simulada, en seis dimensiones (rapidez, corrección, casos límite, comunicación, complejidad y recuperación), centra la mejora en las áreas adecuadas. A continuación, veremos en profundidad cómo abordar los casos límite y las mejores prácticas de comunicación del candidato.
Preguntas frecuentes
¿La lección «Entrevista simulada cronometrada: problemas fáciles y medios» es gratis?
Sí — el texto completo de «Entrevista simulada cronometrada: problemas fáciles y medios» 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 Coding Interview Prep, actualiza a CoddyKit PRO. El curso de Coding Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «Entrevista simulada cronometrada: problemas fáciles y medios»?
Resuelva tres problemas en un tiempo límite de 45 minutos, verbalice su proceso de razonamiento como lo haría en una entrevista real y revise después las soluciones óptimas. Practicas Coding 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 Coding Interview Prep?
No se requiere experiencia previa. Coding 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 2 de 4.
¿Cuánto tiempo toma la lección «Entrevista simulada cronometrada: problemas fáciles y medios»?
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 Coding Interview Prep?
Sí. Cada lección de Coding 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
- Guía rápida de reconocimiento de patrones
- Entrevista simulada cronometrada: problemas fáciles y medios
- Gestión de casos límite y comunicación con el entrevistador
- Resolución guiada de problemas difíciles: Word Ladder II y Alien Dictionary