LeetCode 224, Basic Calculator, verlangt von dir, einen String aus Ziffern, +, -, Klammern und Leerzeichen auszuwerten, ohne eval zu verwenden. Es gibt keine Multiplikation oder Division, also musst du keine Operatorrangfolge beachten. Die einzige Schwierigkeit sind die Klammern, und ein Stack mit gespeicherten Zuständen löst das sauber in einem einzigen Durchlauf.
Das Problem
Gegeben ist ein String s, der einen Ausdruck mit nicht-negativen ganzen Zahlen, +, -, (, ) und Leerzeichen darstellt. Gib seinen Wert zurück. Das Minuszeichen kann auch ein unäres Operator sein, wie in -(2 + 3).
Beispiele:
| Eingabe | Ausgabe |
|---|---|
| "1 + 1" | 2 |
| " 2-1 + 2 " | 3 |
| "(1+(4+5+2)-3)+(6+8)" | 23 |
| "-(3 + (4 + 5))" | -12 |
Die Kernidee
Scanne von links nach rechts und behalte drei Dinge im Blick: das laufende Ergebnis, das aktuelle Vorzeichen und die Zahl, die gerade aufgebaut wird. Wenn du auf eine ( stößt, beginnst du einen Unterausdruck. Speichere das Ergebnis und das Vorzeichen vor der Klammer auf einem Stack und starte dann neu mit Ergebnis 0 und Vorzeichen +1. Wenn du auf eine ) stößt, schließe den Unterausdruck ab, multipliziere ihn mit dem gespeicherten Vorzeichen und addiere ihn zum gespeicherten Ergebnis.
Behandle jedes Zeichen:
| Zeichen | Aktion |
|---|---|
| Ziffer | num = num * 10 + digit |
| + oder - | Addiere sign * num zum Ergebnis, setze num auf 0 zurück, setze das neue Vorzeichen |
| ( | Pushe das Ergebnis und das Vorzeichen, dann setze beide zurück |
| ) | Addiere sign * num zum Ergebnis, multipliziere dann mit dem gespeicherten Vorzeichen und addiere das gespeicherte Ergebnis |
| Leerzeichen | Ignorieren |
Am Ende addierst du das letzte 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
Die Pop-Reihenfolge ist wichtig: Das Vorzeichen wurde zuletzt gepusht, also wird es zuerst gepoppt.
Trace
Ausdruck: 1-(2+3).
| Zeichen | Ergebnis | Vorzeichen | num | Stack |
|---|---|---|---|---|
| 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, dann 5 x (-1) = -5, dann -5 + 1 = -4 | 1 | 0 | [] |
| Ende | -4 |
1 - (2 + 3) = -4, was übereinstimmt.
Unäres Minus
Ein führendes Minus funktioniert ohne speziellen Code. Am Anfang ist num 0, also addiert das erste - sign * 0 zum Ergebnis und setzt dann das Vorzeichen auf -1. Dasselbe gilt nach einer (: Der gespeicherte Zustand setzt result auf 0 und sign auf +1 zurück, also wird (-2) genauso behandelt.
Komplexität
- Zeit: O(n), ein Durchlauf über den String.
- Speicher: O(n) im schlimmsten Fall bei tief verschachtelten Klammern, da der Stack zwei Werte pro geöffneter Klammer speichert.
Ich habe diese Funktion mit 4.000 zufälligen Ausdrücken mit verschachtelten Klammern und unären Minuszeichen getestet und mit Pythons eigener Auswertung verglichen – alle stimmten überein.
Alternative: Rekursion
Du kannst auch eine rekursive Funktion schreiben, die einen Ausdruck parst und sich selbst aufruft, wenn sie auf ( stößt. Das liest sich natürlich, birgt aber das Risiko, bei tief verschachtelter Eingabe das Rekursionslimit zu erreichen, daher ist die Stack-Version in Python sicherer.
Erweiterungen, nach denen Interviewer fragen
| Variation | Was sich ändert |
|---|---|
| Basic Calculator II (LeetCode 227) | Fügt * und / mit Rangfolge hinzu, ohne Klammern. Verwende einen Stack von Termen und wende * und / sofort auf das oberste Element an |
| Basic Calculator III (LeetCode 772) | Hat alles: Klammern sowie * und /. Kombiniere beide Ideen, oft mit Rekursion |
| Variablen oder Funktionen | Erfordert einen Tokenizer und einen Parser |
| Große Zahlen | Verwende Python-Integers oder behandle Overflow in Java und C++ |
Randfälle
| Eingabe | Ergebnis |
|---|---|
| "0" | 0 |
| " 7 " | 7 |
| "-1" | -1 |
| "(1)" | 1 |
| "2-(5-6)" | 3 |
| Viele verschachtelte Klammern | Werden vom Stack behandelt |
| Mehrstellige Zahlen wie "123+4" | 127, weil Ziffern akkumulieren |
Häufige Fehler
- Jede Ziffer als eigene Zahl behandeln.
- Vergessen, am Ende das letzte sign * num zu addieren.
- In der falschen Reihenfolge poppen.
- num nach einem Operator nicht zurücksetzen.
- Ein führendes Minus falsch behandeln.
Wie du es im Interview erklärst
- Kläre die erlaubten Zeichen und ob unäres Minus vorkommt.
- Sag, dass es kein Rangfolgeproblem gibt, also die Klammern die einzige Herausforderung sind.
- Beschreibe die drei Variablen und was ein Stack speichert.
- Gehe 1-(2+3) am Whiteboard durch.
- Nenne die Komplexität und erwähne dann die Calculator-II-Erweiterung.
Verwandte Übungen
Sieh dir unseren Big-O-Spickzettel für die Komplexitätsbegriffe an, den AI-LeetCode-Tutor-Leitfaden und den Leitfaden zum Coding-Interview-Assistenten. Valid Parentheses und Decode String verwenden dieselbe Stack-Idee.
Sprich deinen Trace beim Üben laut mit. Ein Mock-Interview-Transkript zeigt, ob du den Zweck des Stacks erklärt hast. Befolge die Regeln des Arbeitgebers zu KI-Tools in jeder Live-Bewertung.
Übe Coding-Interviews mit YesToTheOffer
Führe ein Mock-Coding-Interview durch, erzähle deinen Trace laut und überprüfe anschließend dein Transkript. 30 kostenlose Minuten, kein Abonnement.



