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 * 105
s
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).This problem requires evaluating a mathematical expression string without using built-in evaluation functions like eval()
. The expression can contain digits, '+', '-', '(', ')', and spaces. The solution uses a stack-based approach to handle operator precedence and parentheses.
Approach:
The core idea is to process the expression iteratively, keeping track of the current running total (ans
), the current sign (sign
), and using a stack to manage nested parentheses.
Initialization:
ans
: Stores the cumulative result. Initialized to 0.sign
: Represents the current sign (+1 or -1). Initialized to +1.stk
: A stack to store intermediate results and signs when encountering parentheses.Iteration: The code iterates through each character in the input string s
.
Character Handling:
ans
based on the current sign
.sign
.ans
and sign
are pushed onto the stack, and ans
and sign
are reset to start calculating the subexpression.sign
and the previous ans
. The current ans
is multiplied by the popped sign and added to the popped ans
, effectively incorporating the subexpression's result into the overall calculation.Time Complexity: O(n), where n is the length of the input string. The algorithm iterates through the string once.
Space Complexity: O(n) in the worst case. The stack can grow up to the maximum depth of nested parentheses, which could be proportional to the length of the string in the worst case.
Code Examples (Python3):
class Solution:
def calculate(self, s: str) -> int:
stack = []
result = 0
sign = 1 # 1 for +, -1 for -
i = 0
while i < len(s):
if s[i].isdigit():
num = 0
while i < len(s) and s[i].isdigit():
num = num * 10 + int(s[i])
i += 1
result += num * sign # Add the number with the current sign
elif s[i] == '+':
sign = 1
i += 1
elif s[i] == '-':
sign = -1
i += 1
elif s[i] == '(':
stack.append(result)
stack.append(sign) # Push the current result and sign onto the stack
result = 0
sign = 1
i += 1
elif s[i] == ')':
result *= stack.pop() # Pop the sign
result += stack.pop() # Pop the previous result and add it to current result
i += 1
else: # Skip spaces
i += 1
return result
The Java, C++, Go, Typescript, and C# examples provided earlier all follow the same fundamental approach and have the same time and space complexity characteristics. They simply differ in syntax and specific library functions used.