Leetcode 224基本计算器
-
题目简述:请实现一个简易计算器,计算一个算数表达式的值。表达式中仅包含左括号
(
、右括号)
、加号+
、减号-
、非负整数 和空格。 -
输入:“1 + 1” 输出:2
输入:" 2-1 + 2 " 输出:3
输入:"(1+(4+5+2)-3)+(6+8)" 输出:23
-
思路:双栈法:利用两个栈一个记录数字,一个记录操作符,然后从前往后扫描表达式
- 如果遇到左括号
(
、+
、-
、直接加入操作符栈中 - 如果遇到数字,则判断操作符栈的栈顶元素,如果该元素是
+
或者-
,就进行相应操作并在操作符栈中弹出完成的操作符,同时更新数字栈顶元素。如果该元素是(
,就继续扫描下一个字符 - 如果遇到
)
,此时操作符栈顶一定是(
,将其弹出。然后根据新的操作符栈顶元素,对数字栈顶的两个元素进行相应计算操作。
代码逻辑先写第三步再写第二步,思考时要按照表达式顺序先看数字再看右括号正常考虑,时间复杂度O(n)
- 如果遇到左括号
class Solution {
public:
void calc(stack<int> &nums, stack<char> &op) {
int n2 = nums.top(); nums.pop();
int n1 = nums.top(); nums.pop();
char c = op.top(); op.pop();
if (c == '+') nums.push(n1 + n2);
else nums.push(n1 - n2);
}
int calculate(string s) {
stack<int> nums;
stack<char> op;
for(int i = 0; i < s.size(); i++)
{
//遇到空格、+-号和左括号
if(s[i] == ' ') continue;
if(s[i] == '+' || s[i] == '-' || s[i] == '(') op.push(s[i]);
else if(s[i] == ')')//遇到右括号
{
op.pop();//此时栈顶一定是左括号,因为+-号已经在数字计算时弹出了
if(op.size() && (op.top() == '-' || op.top() == '+'))
calc(nums, op);
}
else//遇到数字
{
int j = i, n = 0;
//处理多位数,isdigit函数用于判断参数是否是十进制数
while(j < s.size() && isdigit(s[j]))
{
n = n * 10 + (s[j] - '0');
j++;
}
nums.push(n);
//处理多位数等价写法
//while (j < s.size() && isdigit(s[j])) j ++ ;
//num.push(atoi(s.substr(i, j - i).c_str()));
i = j - 1;//恢复原来i的下标位置
if(op.size() && (op.top() == '-' || op.top() == '+'))
calc(nums, op);
}
}
return nums.top();
}
};
- 思路二:单栈法:利用变量
res
记录当前表达式结算结果,sign
记录遇到的运算符,再用栈存储这两个变量- 当遇到左括号时,相当于遇到了一个新子表达式,将两个变量压栈并进行重新赋值
- 当遇到数字时就对数字进行字符转数字处理
- 当遇到加号减号符号时,记录当前结果和运算符,将
1-2
转换成(+1) + (-2)
- 当遇到右括号时,相当于子表达式结束,将当前的子表达式结果累加到栈中的结果上
class Solution {
public:
int calculate(string s) {
int sign = 1, res = 0;
int num = 0;
stack<int> stk;
for(int i = 0; i < s.size(); i++)
{
if(isspace(s[i])) continue;
if(s[i] == '(')
{
stk.push(res);
stk.push(sign);
res = 0;
sign = 1;
}
else if(isdigit(s[i]))
num = num * 10 + (s[i] - '0');
else if(s[i] == '+' || s[i] == '-')
{
res += sign * num;
num = 0;
sign = (s[i] == '+' ? 1 : -1);
}
else if(s[i] == ')')
{
res += sign * num;
res *= stk.top();
stk.pop();
res += stk.top();
stk.pop();
num = 0;
}
}
return res + sign * num;
}
};