LeetCode - 227. 基本计算器 II
问题
227. 基本计算器 II - 力扣(LeetCode)
思路
这道题我会用栈来解决,具体思路是:
- 使用一个栈来存储数字
- 用一个变量记录当前的运算符,初始为'+'
- 用一个变量记录当前处理的数字
然后从左到右扫描表达式,处理过程如下:
- 我们不是立即计算表达式,而是根据运算符的优先级延迟计算
- 对于加减法,我们先把数字压入栈(减法就压入负数)
- 对于乘除法,我们立即与栈顶元素计算,然后将结果压回栈中
- 最后,栈中所有数字相加就是最终结果
这种方法很巧妙地处理了运算符优先级问题,不需要显式比较优先级。
使用单栈+操作符方法处理表达式 '3+5 / 2' 的过程:
初始状态:
- 数字栈:空
- 当前操作符:'+'(默认初始值)
- 当前数字:0
扫描到字符 '3':
- 更新当前数字:num = 3
扫描到字符 '+':
- 根据当前操作符'+' 处理数字3:将3压入栈,栈变为 [3]
- 更新当前操作符:op = '+'
- 重置当前数字:num = 0
扫描到字符 '5':
- 更新当前数字:num = 5
扫描到字符 '/':
- 根据当前操作符'+' 处理数字5:将5压入栈,栈变为 [3, 5]
- 更新当前操作符:op = '/'
- 重置当前数字:num = 0
扫描到字符 '2':
- 更新当前数字:num = 2
到达字符串末尾:
- 根据当前操作符'/' 处理数字2:
- 从栈中弹出顶部元素5
- 计算 5 / 2 = 2(整数除法)
- 将结果2压回栈中,栈变为 [3, 2]
计算最终结果:
- 将栈中所有元素相加:3 + 2 = 5
- 返回结果5
需要注意的几个点:
- 处理多位数字,因为表达式中的数字可能不只是单个数字,使用while循环
- 处理空格,需要跳过
这个算法的时间复杂度是O(n),其中n是字符串的长度,因为我们只需要遍历一次字符串。空间复杂度是O(n),最坏情况下栈可能需要存储所有数字。
读者可能出现的情况
class Solution {
public:int calculate(string s) {stack<int> st;char op = '+';int i = 0;while(i < s.size()){if(s[i] == ' '){i++;}else if(s[i] >= '0' && s[i] <= '9'){int num = 0;while(s[i] >= '0' && s[i] <= '9'){num = num * 10 + (s[i] - '0');i++;}if(op == '+'){st.push(num);}else if(op == '-'){st.push(-num);}else if(op == '*'){int top = st.top();st.pop();st.push(num * top);}else{int top = st.top();st.pop();st.push(num / top);}}else{op = s[i];i++;}}int ret = 0;while(st.size()){ret+=st.top();st.pop();}return ret;}
};
在这段代码中,你将当前读取的数字num作为第一个操作数,将栈顶元素top作为第二个操作数。但实际上,栈顶元素是之前处理的数字,应该是第一个操作数。
例如,对于表达式 "5*2",你的代码会计算 2*5,这虽然结果相同,但对于除法就会出问题。对于 "6/2",你的代码会计算 2/6=0,而正确结果应该是 6/2=3。
正确写法
class Solution {
public:int calculate(string s) {stack<int> st;char op = '+';int i = 0;while(i < s.size()){if(s[i] == ' '){i++;}else if(s[i] >= '0' && s[i] <= '9'){int num = 0;while(s[i] >= '0' && s[i] <= '9'){num = num * 10 + (s[i] - '0');i++;}if(op == '+'){st.push(num);}else if(op == '-'){st.push(-num);}else if(op == '*'){int top = st.top();st.pop();st.push(top * num);}else{int top = st.top();st.pop();st.push(top / num);}}else{op = s[i];i++;}}int ret = 0;while(st.size()){ret+=st.top();st.pop();}return ret;}
};