O LeetCode 224, Basic Calculator, pede que você avalie uma string contendo dígitos, +, -, parênteses e espaços, sem usar eval. Não há multiplicação nem divisão, então não há precedência de operadores para tratar. A única dificuldade são os parênteses, e uma pilha de estados salvos resolve isso de forma limpa em uma única passada.
O problema
Dada uma string s que representa uma expressão com inteiros não negativos, +, -, (, ) e espaços, retorne seu valor. O sinal de menos também pode ser um operador unário, como em -(2 + 3).
Exemplos:
| Entrada | Saída |
|---|---|
| "1 + 1" | 2 |
| " 2-1 + 2 " | 3 |
| "(1+(4+5+2)-3)+(6+8)" | 23 |
| "-(3 + (4 + 5))" | -12 |
A ideia central
Percorra da esquerda para a direita mantendo três coisas: o resultado acumulado, o sinal atual e o número sendo construído. Quando você chega a um (, está prestes a iniciar uma subexpressão. Salve o resultado e o sinal à frente do parêntese em uma pilha, depois comece do zero com resultado 0 e sinal +1. Quando você chega a um ), finalize a subexpressão, multiplique-a pelo sinal salvo e some ao resultado salvo.
Trate cada caractere:
| Caractere | Ação |
|---|---|
| Dígito | num = num * 10 + digit |
| + ou - | Some sign * num ao resultado, reinicie num para 0, defina o novo sinal |
| ( | Empilhe o resultado e o sinal, depois reinicie ambos |
| ) | Some sign * num ao resultado, depois multiplique pelo sinal salvo e some o resultado salvo |
| Espaço | Ignore |
No final, some o ú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
A ordem do desempilhamento importa: o sinal foi empilhado por último, então é desempilhado primeiro.
Traço de execução
Expressão: 1-(2+3).
| Caractere | resultado | sinal | num | pilha |
|---|---|---|---|---|
| 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 depois 5 x (-1) = -5, depois -5 + 1 = -4 | 1 | 0 | [] |
| fim | -4 |
1 - (2 + 3) = -4, o que confere.
Menos unário
Um menos no início funciona sem código especial. No começo, num é 0, então o primeiro - soma sign * 0 ao resultado, depois define o sinal como -1. O mesmo vale depois de um (: o estado salvo reinicia result para 0 e sign para +1, então (-2) é tratado da mesma forma.
Complexidade
- Tempo: O(n), uma passada pela string.
- Espaço: O(n) no pior caso para parênteses profundamente aninhados, já que a pilha guarda dois valores por parêntese aberto.
Testei essa função em 4.000 expressões aleatórias com parênteses aninhados e sinais de menos unário, comparando com a avaliação do próprio Python, e todas bateram.
Alternativa: recursão
Você também pode escrever uma função recursiva que analisa uma expressão e chama a si mesma quando encontra (. Ela é natural de ler, mas corre o risco de estourar o limite de recursão em entradas profundamente aninhadas, então a versão com pilha é mais segura em Python.
Extensões que os entrevistadores pedem
| Variação | O que muda |
|---|---|
| Basic Calculator II (LeetCode 227) | Adiciona * e / com precedência e sem parênteses. Use uma pilha de termos, aplicando * e / imediatamente ao topo |
| Basic Calculator III (LeetCode 772) | Tem tudo: parênteses e * e /. Combine as duas ideias, muitas vezes usando recursão |
| Variáveis ou funções | Precisa de um tokenizador e um parser |
| Números grandes | Use inteiros do Python, ou trate overflow em Java e C++ |
Casos extremos
| Entrada | Resultado |
|---|---|
| "0" | 0 |
| " 7 " | 7 |
| "-1" | -1 |
| "(1)" | 1 |
| "2-(5-6)" | 3 |
| Muitos parênteses aninhados | Tratados pela pilha |
| Números com vários dígitos como "123+4" | 127, porque os dígitos se acumulam |
Erros comuns
- Tratar cada dígito como um número próprio.
- Esquecer de somar o último sign * num no final.
- Desempilhar na ordem errada.
- Não reiniciar num depois de um operador.
- Tratar mal um menos no início.
Como explicar isso em uma entrevista
- Esclareça os caracteres permitidos e se o menos unário aparece.
- Diga que não há problema de precedência, então os parênteses são o único desafio.
- Descreva as três variáveis e o que a pilha salva.
- Percorra 1-(2+3) no quadro branco.
- Dê a complexidade, depois mencione a extensão Calculator II.
Prática relacionada
Veja nosso Big O cheat sheet para os termos de complexidade, o guia de tutor de LeetCode com IA e o guia de assistente de entrevista de programação. Valid Parentheses e Decode String usam a mesma ideia de pilha.
Narre seu traço em voz alta enquanto pratica. Uma transcrição de entrevista simulada mostra se você explicou o propósito da pilha. Siga as regras da empresa sobre ferramentas de IA em qualquer avaliação ao vivo.
Pratique entrevistas de programação com YesToTheOffer
Faça uma entrevista simulada de programação, narre sua execução em voz alta e revise sua transcrição depois. 30 minutos grátis, sem assinatura.



