Evaluate a string of +, -, parentheses and non-negative integers in a single left-to-right scan. A stack remembers the partial result and sign in front of each ( so nested groups fold back in correctly.
Given a valid expression string with +, -, parentheses, spaces and non-negative integers, return its integer value. No * or /, but a leading or unary minus like -(3+2) is allowed. Example: "(1+(4+5+2)-3)+(6+8)". The inner group (4+5+2)=11, so the first group is 1+11-3=9, and (6+8)=14, giving 9+14=23.
result and the sign (+1/-1) that applies to the next number. When you hit (, push the current result and the sign in front of it, then reset to evaluate the inside as a brand-new expression. When you hit ), the inner result is finished — multiply it by the saved sign and add back the saved outer result.That turns arbitrarily nested parentheses into the same flat scan, with the stack acting as memory for "where was I before this group?".
result = 0, sign = +1, num = 0, an empty stack.num = num * 10 + digit. Don't commit yet — more digits may follow.+ / -. Commit the pending number with result += sign * num, reset num = 0, and set sign to +1 or -1 for the next number.(. Push result then sign, then reset both — start the sub-expression fresh.). Commit the last inner number, then result = result * stack.pop() + stack.pop() (saved sign, then saved outer total).result + sign * num to commit any trailing number.- is a sign on the next number, not a binary subtraction you do immediately. You never "subtract"; you fold sign * num into result. This is also why multi-digit numbers must be built up (num * 10 + digit) and only committed at the next operator, paren, or end of string.() span and re-scan it; nested groups get re-read many times.You can solve it with explicit recursion (treat each ( as a recursive call), but the iterative stack version is the same idea with the call stack made explicit — and avoids re-scanning.
(" scan generalizes to Basic Calculator II (add *// via a number stack), Basic Calculator III (both, with parens), Decode String (push count + built string on [), and Evaluate Reverse Polish Notation."(1+(4+5+2)-3)+(6+8)" left to right. Start with result=0, sign=+1, num=0, empty stack.1function calculate(s: string): number {2▶ let result = 0; // running total of the current level3▶ let sign = 1; // +1 or -1 applied to the next number4▶ let num = 0; // the integer currently being built5▶ const stack: number[] = []; // saved (result, sign) pairs67 for (const ch of s) {8 if (ch >= '0' && ch <= '9') {9 num = num * 10 + (ch.charCodeAt(0) - 48); // build multi-digit10 } else if (ch === '+') {11 result += sign * num; // commit the pending number12 num = 0;13 sign = 1;14 } else if (ch === '-') {15 result += sign * num;16 num = 0;17 sign = -1;18 } else if (ch === '(') {19 stack.push(result); // save the outer total...20 stack.push(sign); // ...and the sign in front of '('21 result = 0; // start a fresh sub-expression22 sign = 1;23 } else if (ch === ')') {24 result += sign * num; // commit last number inside ()25 num = 0;26 result *= stack.pop()!; // apply the saved sign27 result += stack.pop()!; // add back the outer total28 }29 // spaces fall through and are ignored30 }31 return result + sign * num; // commit any trailing number32}
function calculate(s: string): number {
let result = 0; // running total of the current level
let sign = 1; // +1 or -1 applied to the next number
let num = 0; // the integer currently being built
const stack: number[] = []; // saved (result, sign) pairs
for (const ch of s) {
if (ch >= '0' && ch <= '9') {
num = num * 10 + (ch.charCodeAt(0) - 48); // build multi-digit
} else if (ch === '+') {
result += sign * num; // commit the pending number
num = 0;
sign = 1;
} else if (ch === '-') {
result += sign * num;
num = 0;
sign = -1;
} else if (ch === '(') {
stack.push(result); // save the outer total...
stack.push(sign); // ...and the sign in front of '('
result = 0; // start a fresh sub-expression
sign = 1;
} else if (ch === ')') {
result += sign * num; // commit last number inside ()
num = 0;
result *= stack.pop()!; // apply the saved sign
result += stack.pop()!; // add back the outer total
}
// spaces fall through and are ignored
}
return result + sign * num; // commit any trailing number
}result is the total of the current parenthesis level, sign is the +1/-1 waiting in front of the next number, num is the integer being assembled digit by digit, and stack stores (outer result, saved sign) pairs.num = num * 10 + digit so multi-digit integers like 42 form correctly. charCodeAt(0) - 48 converts the digit char to its value.+ or - means the current number is final: fold sign * num into result, reset num, and store the new sign for what comes next.result and sign to freeze the outer state, then zero both so the sub-expression starts clean.result *= stack.pop() applies the saved sign (the one in front of the () and result += stack.pop() adds back the outer total.result + sign * num.(, bounded by the nesting depth, so O(n) space in the worst case.* and / too." (LC 227 / 772) Keep a stack of numbers; on *// immediately combine with the stack top so precedence is handled, then sum the stack at the end.-3 or -(2+1)." Initialising num = 0 and result = 0 means a leading - already works — it just sets sign = -1 with result still 0.( is a recursive call returning the inner value and the index it stopped at. The iterative stack makes the same call-stack explicit and avoids deep recursion limits.function calculate(s: string): number {
let result = 0; // running total of the current level
let sign = 1; // +1 or -1 applied to the next number
let num = 0; // the integer currently being built
const stack: number[] = []; // saved (result, sign) pairs
for (const ch of s) {
if (ch >= '0' && ch <= '9') {
num = num * 10 + (ch.charCodeAt(0) - 48); // build multi-digit
} else if (ch === '+') {
result += sign * num; // commit the pending number
num = 0;
sign = 1;
} else if (ch === '-') {
result += sign * num;
num = 0;
sign = -1;
} else if (ch === '(') {
stack.push(result); // save the outer total...
stack.push(sign); // ...and the sign in front of '('
result = 0; // start a fresh sub-expression
sign = 1;
} else if (ch === ')') {
result += sign * num; // commit last number inside ()
num = 0;
result *= stack.pop()!; // apply the saved sign
result += stack.pop()!; // add back the outer total
}
// spaces fall through and are ignored
}
return result + sign * num; // commit any trailing number
}(, bounded by the nesting depth, so O(n) space in the worst case.Treat each ( as a recursive call that evaluates the inner expression and returns both its value and the index just past its ).
function calculate(s: string): number {
// Evaluate s starting at index i (just after an optional '(').
// Returns the value of this level and the index AFTER its matching ')'
// (or s.length for the top level).
function eval(i: number): [number, number] {
let result = 0; // running total of this level
let sign = 1; // +1 or -1 applied to the next number
let num = 0; // integer currently being built
let haveNum = false;
while (i < s.length) {
const ch = s[i];
if (ch >= '0' && ch <= '9') {
num = num * 10 + (ch.charCodeAt(0) - 48); // build multi-digit
haveNum = true;
i++;
} else if (ch === '+') {
result += sign * num; // commit pending number
num = 0;
haveNum = false;
sign = 1;
i++;
} else if (ch === '-') {
result += sign * num;
num = 0;
haveNum = false;
sign = -1;
i++;
} else if (ch === '(') {
// Recurse on the sub-expression starting just after '('
const [inner, next] = eval(i + 1);
num = inner; // the group's value acts like one number
haveNum = true;
i = next; // jump past the matching ')'
} else if (ch === ')') {
// End of this level: commit and hand back the index past ')'
if (haveNum) result += sign * num;
return [result, i + 1];
} else {
i++; // skip spaces
}
}
// Top level reached the end of the string
if (haveNum) result += sign * num;
return [result, i];
}
return eval(0)[0];
}( opens a frame and the matching ) returns its value plus the resume index, so the caller can continue exactly where the group ended. Clean to reason about, but a deeply nested input could overflow the recursion limit.One stack of operands and one of operators, applying lower-precedence ops before pushing — the textbook shunting-style evaluator that extends straight to * and /.
function calculate(s: string): number {
const nums: number[] = []; // operand stack
const ops: string[] = []; // operator stack ('+', '-', '(')
// Pop the top operator and apply it to the top two operands.
function apply(): void {
const b = nums.pop()!;
const a = nums.pop()!;
const op = ops.pop()!;
nums.push(op === '+' ? a + b : a - b);
}
// '+' and '-' share precedence 1; '(' is a barrier with precedence 0.
function prec(op: string): number {
return op === '+' || op === '-' ? 1 : 0;
}
let i = 0;
let prevWasOperand = false; // distinguishes unary '-' from binary '-'
while (i < s.length) {
const ch = s[i];
if (ch === ' ') {
i++;
} else if (ch >= '0' && ch <= '9') {
let num = 0;
while (i < s.length && s[i] >= '0' && s[i] <= '9') {
num = num * 10 + (s.charCodeAt(i) - 48); // build multi-digit
i++;
}
nums.push(num);
prevWasOperand = true;
} else if (ch === '(') {
ops.push('(');
prevWasOperand = false;
i++;
} else if (ch === ')') {
while (ops.length > 0 && ops[ops.length - 1] !== '(') apply();
ops.pop(); // discard the matching '('
prevWasOperand = true;
i++;
} else {
// ch is '+' or '-'
// A '-' with no operand before it (start, after '(' or another op) is unary.
if (ch === '-' && !prevWasOperand) {
nums.push(0); // turn unary minus into 0 - x
}
while (
ops.length > 0 &&
ops[ops.length - 1] !== '(' &&
prec(ops[ops.length - 1]) >= prec(ch)
) {
apply(); // flush equal/higher precedence before pushing
}
ops.push(ch);
prevWasOperand = false;
i++;
}
}
while (ops.length > 0) apply();
return nums.pop()!;
}* and / (Basic Calculator II / III) you only give them precedence 2 in prec and extend apply — the rest is unchanged.| expression with + - and parentheses | running result + sign, stack on ( |
| nested groups change scope | push (result, sign) before recursing in |
| multi-digit non-negative integers | num = num*10 + digit, commit later |
| add * and / with precedence | stack of numbers (Calculator II) |
let result = 0, sign = 1, num = 0;
const stack: number[] = [];
for (const ch of s) {
if (ch >= '0' && ch <= '9') num = num * 10 + (+ch);
else if (ch === '+') { result += sign * num; num = 0; sign = 1; }
else if (ch === '-') { result += sign * num; num = 0; sign = -1; }
else if (ch === '(') { stack.push(result, sign); result = 0; sign = 1; }
else if (ch === ')') {
result += sign * num; num = 0;
result = result * stack.pop()! + stack.pop()!;
}
}
return result + sign * num;result (total of this level), sign (+1/-1 for the next number), and num (the integer being built)."(1+(4+5+2)-3)+(6+8)" evaluate to?), which expression correctly closes the group (saved sign then saved outer result)?