Overflow in intermediate arithmetic
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
Given a string s representing a valid expression, implement a basic calculator to evaluate it, and return the result of the evaluation.
Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().
Example 1:
Input: s = "1 + 1" Output: 2
Example 2:
Input: s = " 2-1 + 2 " Output: 3
Example 3:
Input: s = "(1+(4+5+2)-3)+(6+8)" Output: 23
Constraints:
1 <= s.length <= 3 * 105s consists of digits, '+', '-', '(', ')', and ' '.s represents a valid expression.'+' is not used as a unary operation (i.e., "+1" and "+(2 + 3)" is invalid).'-' could be used as a unary operation (i.e., "-1" and "-(2 + 3)" is valid).Problem summary: Given a string s representing a valid expression, implement a basic calculator to evaluate it, and return the result of the evaluation. Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Math · Stack
"1 + 1"
" 2-1 + 2 "
"(1+(4+5+2)-3)+(6+8)"
evaluate-reverse-polish-notation)basic-calculator-ii)different-ways-to-add-parentheses)expression-add-operators)basic-calculator-iii)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #224: Basic Calculator
class Solution {
public int calculate(String s) {
Deque<Integer> stk = new ArrayDeque<>();
int sign = 1;
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
int j = i;
int x = 0;
while (j < n && Character.isDigit(s.charAt(j))) {
x = x * 10 + s.charAt(j) - '0';
j++;
}
ans += sign * x;
i = j - 1;
} else if (c == '+') {
sign = 1;
} else if (c == '-') {
sign = -1;
} else if (c == '(') {
stk.push(ans);
stk.push(sign);
ans = 0;
sign = 1;
} else if (c == ')') {
ans = stk.pop() * ans + stk.pop();
}
}
return ans;
}
}
// Accepted solution for LeetCode #224: Basic Calculator
func calculate(s string) (ans int) {
stk := []int{}
sign := 1
n := len(s)
for i := 0; i < n; i++ {
switch s[i] {
case ' ':
case '+':
sign = 1
case '-':
sign = -1
case '(':
stk = append(stk, ans)
stk = append(stk, sign)
ans, sign = 0, 1
case ')':
ans *= stk[len(stk)-1]
stk = stk[:len(stk)-1]
ans += stk[len(stk)-1]
stk = stk[:len(stk)-1]
default:
x := 0
j := i
for ; j < n && '0' <= s[j] && s[j] <= '9'; j++ {
x = x*10 + int(s[j]-'0')
}
ans += sign * x
i = j - 1
}
}
return
}
# Accepted solution for LeetCode #224: Basic Calculator
class Solution:
def calculate(self, s: str) -> int:
stk = []
ans, sign = 0, 1
i, n = 0, len(s)
while i < n:
if s[i].isdigit():
x = 0
j = i
while j < n and s[j].isdigit():
x = x * 10 + int(s[j])
j += 1
ans += sign * x
i = j - 1
elif s[i] == "+":
sign = 1
elif s[i] == "-":
sign = -1
elif s[i] == "(":
stk.append(ans)
stk.append(sign)
ans, sign = 0, 1
elif s[i] == ")":
ans = stk.pop() * ans + stk.pop()
i += 1
return ans
// Accepted solution for LeetCode #224: Basic Calculator
struct Solution;
use std::iter::Peekable;
use std::str::Chars;
use std::vec::IntoIter;
#[derive(Debug)]
enum Tok {
Num(i32),
Op(char),
}
impl Solution {
fn calculate(s: String) -> i32 {
let mut it = s.chars().peekable();
let tokens = Self::parse_tokens(&mut it);
let mut it = tokens.into_iter().peekable();
Self::parse(&mut it)
}
fn parse_term(it: &mut Peekable<IntoIter<Tok>>) -> i32 {
if Self::eat(it, '(') {
let res = Self::parse(it);
Self::eat(it, ')');
res
} else {
if let Some(Tok::Num(x)) = it.next() {
x
} else {
panic!()
}
}
}
fn parse(it: &mut Peekable<IntoIter<Tok>>) -> i32 {
let mut left = Self::parse_term(it);
loop {
if Self::eat(it, '+') {
left += Self::parse_term(it);
continue;
}
if Self::eat(it, '-') {
left -= Self::parse_term(it);
continue;
}
break;
}
left
}
fn eat(it: &mut Peekable<IntoIter<Tok>>, c: char) -> bool {
if let Some(&Tok::Op(first)) = it.peek() {
if first == c {
it.next();
return true;
}
}
false
}
fn parse_tokens(it: &mut Peekable<Chars>) -> Vec<Tok> {
let mut res = vec![];
while let Some(c) = it.next() {
match c {
'0'..='9' => {
let mut x = (c as u8 - b'0') as i32;
while let Some('0'..='9') = it.peek() {
x *= 10;
x += (it.next().unwrap() as u8 - b'0') as i32;
}
res.push(Tok::Num(x));
}
'(' | ')' | '+' | '-' => {
res.push(Tok::Op(c));
}
_ => {}
}
}
res
}
}
#[test]
fn test() {
let s = "1 + 1".to_string();
let res = 2;
assert_eq!(Solution::calculate(s), res);
let s = " 2-1 + 2 ".to_string();
let res = 3;
assert_eq!(Solution::calculate(s), res);
let s = "(1+(4+5+2)-3)+(6+8)".to_string();
let res = 23;
assert_eq!(Solution::calculate(s), res);
}
// Accepted solution for LeetCode #224: Basic Calculator
function calculate(s: string): number {
const stk: number[] = [];
let sign = 1;
let ans = 0;
const n = s.length;
for (let i = 0; i < n; ++i) {
if (s[i] === ' ') {
continue;
}
if (s[i] === '+') {
sign = 1;
} else if (s[i] === '-') {
sign = -1;
} else if (s[i] === '(') {
stk.push(ans);
stk.push(sign);
ans = 0;
sign = 1;
} else if (s[i] === ')') {
ans *= stk.pop() as number;
ans += stk.pop() as number;
} else {
let x = 0;
let j = i;
for (; j < n && !isNaN(Number(s[j])) && s[j] !== ' '; ++j) {
x = x * 10 + (s[j].charCodeAt(0) - '0'.charCodeAt(0));
}
ans += sign * x;
i = j - 1;
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
For each element, scan left (or right) to find the next greater/smaller element. The inner scan can visit up to n elements per outer iteration, giving O(n²) total comparisons. No extra space needed beyond loop variables.
Each element is pushed onto the stack at most once and popped at most once, giving 2n total operations = O(n). The stack itself holds at most n elements in the worst case. The key insight: amortized O(1) per element despite the inner while-loop.
Review these before coding to avoid predictable interview regressions.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Wrong move: Pushing without popping stale elements invalidates next-greater/next-smaller logic.
Usually fails on: Indices point to blocked elements and outputs shift.
Fix: Pop while invariant is violated before pushing current element.