LeetCode 224, Basic Calculator, te pide evaluar una cadena que contiene dígitos, +, -, paréntesis y espacios, sin usar eval. No hay multiplicación ni división, así que no hay precedencia de operadores que manejar. La única dificultad son los paréntesis, y una pila de estados guardados lo resuelve limpiamente en una sola pasada.
El problema
Dada una cadena s que representa una expresión con enteros no negativos, +, -, (, ) y espacios, devuelve su valor. El signo menos también puede ser un operador unario, como en -(2 + 3).
Ejemplos:
| Entrada | Salida |
|---|---|
| "1 + 1" | 2 |
| " 2-1 + 2 " | 3 |
| "(1+(4+5+2)-3)+(6+8)" | 23 |
| "-(3 + (4 + 5))" | -12 |
La idea clave
Recorre de izquierda a derecha manteniendo tres cosas: el resultado acumulado, el signo actual y el número que estás construyendo. Cuando llegas a un (, estás a punto de empezar una subexpresión. Guarda el resultado y el signo que precede al paréntesis en una pila, y luego empieza de cero con resultado 0 y signo +1. Cuando llegas a un ), termina la subexpresión, multiplícala por el signo guardado y súmala al resultado guardado.
Maneja cada carácter:
| Carácter | Acción |
|---|---|
| Dígito | num = num * 10 + digit |
| + o - | Suma sign * num al resultado, reinicia num a 0, establece el nuevo signo |
| ( | Apila el resultado y el signo, luego reinicia ambos |
| ) | Suma sign * num al resultado, luego multiplica por el signo guardado y suma el resultado guardado |
| Espacio | Ignóralo |
Al final, suma el último sign * num.
def calculate(s):
result, sign, num = 0, 1, 0
stack = []
for ch in s:
if ch.isdigit():
num = num * 10 + int(ch)
elif ch in "+-":
result += sign * num
num = 0
sign = 1 if ch == "+" else -1
elif ch == "(":
stack.append(result)
stack.append(sign)
result, sign = 0, 1
elif ch == ")":
result += sign * num
num = 0
result *= stack.pop() # the sign before the parenthesis
result += stack.pop() # the result before the parenthesis
return result + sign * num
El orden de desapilado importa: el signo se apiló al último, así que se desapila primero.
Traza
Expresión: 1-(2+3).
| Carácter | resultado | signo | num | pila |
|---|---|---|---|---|
| 1 | 0 | 1 | 1 | [] |
| - | 1 | -1 | 0 | [] |
| ( | 0 | 1 | 0 | [1, -1] |
| 2 | 0 | 1 | 2 | [1, -1] |
| + | 2 | 1 | 0 | [1, -1] |
| 3 | 2 | 1 | 3 | [1, -1] |
| ) | 5, luego 5 x (-1) = -5, luego -5 + 1 = -4 | 1 | 0 | [] |
| fin | -4 |
1 - (2 + 3) = -4, lo cual coincide.
Menos unario
Un menos al inicio funciona sin código especial. Al comenzar, num es 0, así que el primer - suma sign * 0 al resultado y luego establece el signo a -1. Lo mismo aplica después de un (: el estado guardado reinicia result a 0 y sign a +1, así que (-2) se maneja de la misma forma.
Complejidad
- Tiempo: O(n), una sola pasada sobre la cadena.
- Espacio: O(n) en el peor caso para paréntesis muy anidados, ya que la pila guarda dos valores por cada paréntesis de apertura.
Probé esta función con 4.000 expresiones aleatorias con paréntesis anidados y signos menos unarios, comparando con la evaluación propia de Python, y todas coincidieron.
Alternativa: recursión
También puedes escribir una función recursiva que parsee una expresión y se llame a sí misma cuando encuentre un (. Se lee de forma natural, pero corre el riesgo de alcanzar el límite de recursión con entradas muy anidadas, así que la versión con pila es más segura en Python.
Extensiones que piden los entrevistadores
| Variación | Qué cambia |
|---|---|
| Basic Calculator II (LeetCode 227) | Agrega * y / con precedencia y sin paréntesis. Usa una pila de términos, aplicando * y / de inmediato al tope |
| Basic Calculator III (LeetCode 772) | Tiene todo: paréntesis y * y /. Combina ambas ideas, a menudo usando recursión |
| Variables o funciones | Requiere un tokenizador y un parser |
| Números grandes | Usa enteros de Python, o maneja el desbordamiento en Java y C++ |
Casos límite
| Entrada | Resultado |
|---|---|
| "0" | 0 |
| " 7 " | 7 |
| "-1" | -1 |
| "(1)" | 1 |
| "2-(5-6)" | 3 |
| Muchos paréntesis anidados | Los maneja la pila |
| Números de varios dígitos como "123+4" | 127, porque los dígitos se acumulan |
Errores comunes
- Tratar cada dígito como su propio número.
- Olvidar sumar el último sign * num al final.
- Desapilar en el orden equivocado.
- No reiniciar num después de un operador.
- Manejar mal un menos al inicio.
Cómo explicarlo en una entrevista
- Aclara los caracteres permitidos y si aparece el menos unario.
- Di que no hay problema de precedencia, así que los paréntesis son el único desafío.
- Describe las tres variables y qué guarda una pila.
- Recorre 1-(2+3) en la pizarra.
- Da la complejidad y luego menciona la extensión Calculator II.
Práctica relacionada
Consulta nuestra guía rápida de Big O para los términos de complejidad, la guía del tutor de LeetCode con IA y la guía del asistente para entrevistas de programación. Valid Parentheses y Decode String usan la misma idea de pila.
Narra tu traza en voz alta mientras practicas. Una transcripción de entrevista simulada muestra si explicaste el propósito de la pila. Sigue las reglas del empleador sobre herramientas de IA en cualquier evaluación en vivo.
Practica entrevistas de programación con YesToTheOffer
Realiza una entrevista de programación simulada, narra tu seguimiento en voz alta y revisa tu transcripción después. 30 minutos gratis, sin suscripción.



