用栈模拟数学表达式计算
这类题包括数字的加减乘除运算,有基本计算器、逆波兰表达式等;
150 逆波兰表达式
解题思路
这题的解题思路就是,用一个栈去存储每一个字符串,遇到数字直接入栈,遇到运算符就先做运算。
class Solution {
public:
int to_digit(string s){
int n=s.size();
int sum=0;
for(int i=0;i<n;i++){
if('0'<=s[i]&&s[i]<='9'){
sum=sum*10+s[i]-'0';
}
}
//判断是否是负数;
return s[0]=='-'?-1*sum:sum;
}
int evalRPN(vector<string>& tokens) {
int n=tokens.size();
stack<int>nums;
for(int i=0;i<n;i++){
//先判断是否是运算符,因为运算符肯定长度只有一位;
if(tokens[i].size()==1){
char str=tokens[i][0];
//如果是数字,直接入栈:
if('0'<=str&&str<='9'){
nums.push(str-'0');
//不是数字,进行运算;
}else{
int a=nums.top();nums.pop();
int b=nums.top();nums.pop();
switch (str){
case '+':nums.push(a+b);break;
case '-':nums.push(b-a);break;
case '*':nums.push(a*b);break;
case '/':nums.push(b/a);break;
}
}
}
//长度不为1,则肯定是数字,转换为数字直接入栈
else nums.push(to_digit(tokens[i]));
}
//最后的结果一定在栈顶
return nums.top();
}
};
224 基本计算器
基本计算器
解题思路:
通用的解法是利用两个栈,一个存数字,一个存运算符
代码实现:
class Solution {
public:
stack<long>nums;
stack<char>ops;
void cal(){
int a=nums.top();nums.pop();
int b=nums.top();nums.pop();
char op=ops.top();ops.pop();
switch(op){
case '+':nums.push(a+b);break;
//注意这里是b-a,因为栈是先进后出
case '-':nums.push(b-a);break;
case '*':nums.push(a*b);break;
case '/':nums.push(b/a);break;
}
}
int calculate(string s) {
unordered_map<char,int>mp;
mp.insert(make_pair('+',1));
mp.insert(make_pair('-',1))
mp.insert(make_pair('*',2));
mp.insert(make_pair('/',2));
int n=s.size();
int i=0;
nums.push(0);
while(i<n){
//如果是空格,直接跳过
if(s[i]==' '){
i++;
continue;
//如果是左括号,入ops栈
}else if(s[i]=='('){
ops.push(s[i]);
i++;
//如果是右括号,计算栈内元素,直到碰到左括号
}else if(s[i]==')'){
while(ops.top()!='('){
cal();
}
//将左括号弹出
ops.pop();
i++;
//如果是数字,可能存在45,333等数字,拼接起来存入nums;
}else if(isdigit(s[i])){
long d=s[i]-'0';
int j=i+1;
while(j<n&&isdigit(s[j])){
d=d*10+s[j]-'0';
j++;
}
nums.push(d);
i=j;
//如果是符号操作,先执行所有栈里面的操作,直到没有操作或者碰到左括号
}else{
//如果栈顶的优先级高于新进来的的运算符,那就先执行栈顶的运算符;
while(!ops.empty()&&mp[ops.top()]>=mp[s[i]]){
cal();
}
ops.push(s[i]);
i++;
}
}
while(!ops.empty()){
cal();
}
return nums.top();
}
};
227 基本计算器II
class Solution {
public:
stack<long>nums;
stack<char>ops;
void cal(){
long a=nums.top();nums.pop();
long b=nums.top();nums.pop();
char c=ops.top();ops.pop();
switch(c){
case '+':nums.push(a+b);break;
case '-':nums.push(b-a);break;
case '*':nums.push(a*b);break;
case '/':nums.push(b/a);break;
}
}
int calculate(string s) {
int n=s.size();
unordered_map<char,int>mp;
mp.insert(make_pair('+',1));
mp.insert(make_pair('-',1));
mp.insert(make_pair('*',2));
mp.insert(make_pair('/',2));
int i=0;
while(i<n){
if(s[i]==' '){
i++;
continue;
}else if(isdigit(s[i])){
long d=s[i]-'0';
int j=i+1;
while(j<n&&isdigit(s[j])){
d=10*d+s[j]-'0';
j++;
}
nums.push(d);
i=j;
}else{
while(!ops.empty()&&mp[ops.top()]>=mp[s[i]]){
cal();
}
ops.push(s[i]);
i++;
}
}
while(!ops.empty()){
cal();
}
return nums.top();
}
};
1006 笨阶乘
笨阶乘
双栈解法
利用上面的解题思路即可解决
class Solution {
public:
stack<int>nums;
stack<char>ops;
void cal(){
int a=nums.top();nums.pop();
int b=nums.top();nums.pop();
char op=ops.top();ops.pop();
switch(op){
case '+':nums.push(a+b);break;
//注意这里是b-a,因为栈是先进后出
case '-':nums.push(b-a);break;
case '*':nums.push(a*b);break;
case '/':nums.push(b/a);break;
}
}
int clumsy(int N) {
char op[4]={'*','/','+','-'};
unordered_map<char,int>mp;
mp.insert(make_pair('+',1));
mp.insert(make_pair('-',1));
mp.insert(make_pair('*',2));
mp.insert(make_pair('/',2));
for(int i=N,j=0;i>0;i--,j++){
char option=op[j%4];
nums.push(i);
while(!ops.empty()&&mp[option]<=mp[ops.top()]){
cal();
}
if(i!=1) ops.push(option);
}
while(!ops.empty()) cal();
return nums.top();
}
};
解题思路
出现乘法、除法的时候可以把栈顶元素取出,与当前的 N进行乘法运算、除法运算(除法运算需要注意先后顺序),并将运算结果重新压入栈
出现加法、减法的时候,把减法视为加上一个数的相反数,然后压入栈,等待以后遇见「乘」「除」法的时候取出。
最后将栈里面的元素累加即为答案。
代码实现
class Solution {
public:
int clumsy(int N) {
stack<int>sta;
sta.push(N);
N--;
int index=0;
//遇到乘法和除法直接运算,遇到加法和减法就入栈,其中减法push相反数;
while(N>0){
if(index%4==0){
sta.top()*=N;
}else if(index%4==1){
sta.top()/=N;
}else if(index%4==2){
sta.push(N);
}else {
sta.push(-N);
}
N--;
index++;
}
int sum=0;
while(!sta.empty()){
sum+=sta.top();
sta.pop();
}
return sum;
}
};