一. 带乘除不带括号的计算器
这题属于计算器问题中比较简单的,首先不带括号所以不用考虑括号匹配的问题,然后我们知道“先乘除后加减”,所以对于乘除应该直接求出结果,对于加减法来说应当记录每个数字前面的正负号然后直接将带符号的数入栈。还要注意的一点是,需要计算连续数字字符子串的十进制表达,这点好实现。最后栈中应当全部是带符号的数,对他们全部求和即可!
例如:3-24,遇到数字4的时候,因为其前面的符号是,所以用栈顶的-2乘以4 = -8,所以栈内是3,-8,结果就是-5!
class Solution {
public:
int calculate(string s) {
vector<int> st;
char presign = '+'; // 用于记录数字前面的符号
int num = 0;
for(int i=0;i<s.size();i++){
if(s[i]!='+'&&s[i]!='-'&&s[i]!='*'&&s[i]!='/'&&s[i]!=' '){
num = num*10 + (s[i]-'0');
}
if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/'||i == s.size()-1){ // 这里的i == s.size()-1的情况比较特使,处于字符串的末尾,一定是一个数字,因此也需要输出结果
switch(presign){
case '+':
st.push_back(num);
break;
case '-':
st.push_back(-num);
break;
case '*':
st.back() *= num;
break;
case '/':
st.back() /= num;
break;
}
presign = s[i];
num = 0;
}
}
int res = 0;
for(int i=0;i<st.size();i++)
res+=st[i];
return res;
}
};
二. 带括号不带乘除的计算器
这题因为引入了括号所以需要进行括号匹配,那么试想一下括号在这种场景下影响了什么呢?其实就是括号前面的正负号会影响整个括号内结果的正负性!因此对于每个闭合的括号我们需要单独计算括号内部的结果,然后根据括号前面的正负号来确定结果的正负性!所以我们需要通过栈来记录每个"(“前面的符,在遇到”)“的时候根据栈顶对应的正负号和括号内计算的结果得出这个闭合括号正确的值!既然每次进入一个括号的时候需要单独记录括号内的结果,那么括号前面所得到的结果就应该再建一个结果栈来保存!所以每当遇到”)"的时候需要计算得到括号内正确的结果然后再和结果栈的栈顶相加!
总的来说,一个符号栈用于维护每个”(“前的符号,一个结果栈用于维护每个”(“前的结果,每次遇到”)"代表完成一个闭合括号内的计算,需要对符号栈和结果栈的栈顶进行计算并出栈
参考别人很好的题解:https://leetcode-cn.com/problems/basic-calculator/solution/shuang-zhan-shuang-90-by-cyingenohalt-eoy3/
class Solution {
public:
int calculate(string s) {
int presign = 1; // 符号先初始化为1,1代表正,-1代表负
int ans = 0; // 结果初始化为0
// 两个栈,一个用于存放(前的符号,一个用来存放(前的结果
stack<int> s_flag; // 符号栈
stack<int> s_num; // 结果栈
for(int i=0;i<s.size();i++){
if(s[i]>='0'&&s[i]<='9'){ // 对于数字,直接求出连续数字字串的十进制数值
int num = 0;
while(i<s.size()&&s[i]>='0'&&s[i]<='9'){
num = num*10 + (s[i]-'0');
i++;
}
ans += num*presign; // 结合数字前面的正负号并入当前结果ans
}
if(s[i]!=' '){
switch(s[i]){
case '+':
presign = 1; // 更新presign
break;
case '-':
presign = -1;
break;
case '(':
s_flag.push(presign); // 遇到(的时候需要将其前面的符号入栈
presign = 1; // 这里也是一个关键,这时的presign代表的是括号内了,因此也初始化为1
s_num.push(ans); // 将(前面的结果入栈,因为进入括号后要开始括号内部结果的计算
ans = 0;
break;
case ')':
int flag = s_flag.top();
int tmp = flag*ans; // 根据符号栈所记录括号前面的符号和括号内的无符号结果计算出真实结果
s_flag.pop();
ans = s_num.top() + tmp; // 当前的闭合括号计算完毕,将结果栈保存的括号前结果出栈求和并继续计算
s_num.pop();
break;
}
}
}
return ans;
}
};
可以通用于计算器问题的一点:对于加减法,我们需要记录每个数字前面的符号,遇到带括号的问题,需要记录括号前面的符号!所以±符号在计算器问题中是“滞后的”,每次遇到±需要更新当前符号,遇到数字就可以利用当前符号来得到带符号数字结果!