公式字符串求值

https://www.nowcoder.com/practice/c590e97ee1f6462d871430feee055d25tpId=101&tqId=33196&tPage=1&rp=1&ru=/ta/programmer-code-interview-guide&qru=/ta/programmer-code-interview-guide/question-ranking

题目描述

给定一个字符串str,str表示一个公式,公式里可以有整数,加减乘除和左右括号,返回公式的计算结果(注意:题目中所有运算都是整型运算,向下取整,且保证数据合法,不会出现除0等情况)。

输入描述:

输出一行字符串,代表str(1≤lengthstr​≤1000)(保证str计算的结果不会出现除零,int溢出等情况)。

输出描述:

输出一个整数,代表表达式的计算结果。

示例1

输入

48*((70-65)-43)+8*1

输出

-1816

示例2

输入

3+1*4

输出

7

算法思路:字符串给定值是中缀表达式,计算机无法直接计算,需要转换成后缀表达式(逆波兰表达式),中缀转后缀形式不唯一,但是计算结果是一致的,因为对于同一级运算,先计算前面在计算后面和先计算后面在计算前面一样。不过,后缀表达式转换成中缀表达式则是唯一的。

一般转换方法:使用两个栈,一个数字栈,一个运算符栈,在转换过程中不断计算

遍历字符串中每一个字符

1、如果是数字字符,则不断通过字符到数字的转换,然后将数字压入数字栈;

2、如果是运算符,此时运算符栈为空,直接压入该运算符,否则,不断弹出运算符栈中优先级不低于该运算符的字符

     弹出的时候顺便调用计算函数calculate计算,直到遇到'(',直接弹出;

3、如果是左右括号:如果是左括号'(',直接入运算符栈,否则是右括号')',不断弹出运算符栈,并计算,直到遇到左括号'(',弹       出左括号'('结束;

4、遍历完每一个字符后,如果运算符栈还不空,不断取里面的运算符并计算,最后数字栈中就剩一个元素,即为最终的结果。

注意:这里没有考虑数字前面有负号运算符的情况,比如-4+3=-1,这里不能简单的认为'-'是减号运算符,在代码中有一个if语句用来处理这种情况。(一般情况,我们认为没有这种情况,并假定输入都是合法和规矩的,但是这边OJ有这种测试案例,不加大概通过90%,加上ac)

#include<bits/stdc++.h>
using namespace std;
int getPriority(char& ch){
    if(ch=='(') return 1;
    if(ch=='+' || ch=='-') return 2;
    if(ch=='*' || ch=='/') return 3;
    return 4;
}

void calculate(stack<int>& numStk,char& opr){
    int num2=numStk.top();
    numStk.pop();
    int num1=numStk.top();
    numStk.pop();
    int res=0;
    if(opr=='+'){
        res=num1+num2;
    }else if(opr=='-'){
        res=num1-num2;
    }else if(opr=='*'){
        res=num1*num2;
    }else{ //opr=='/'
        res=num1/num2;
    }
    numStk.push(res);
    return;
}

int main(){
    string s;
    cin>>s;
    stack<int> numStk;
    stack<char> oprStk;
    int i=0;
    int n=s.size();
    char tmp_opr;
    int flag=0;
    if(s[0]=='-'){
        i=1;
        flag=1;
    }

    while(i<n){
        if( s[i]=='-' && s[i-1]!=')' && (s[i-1]<'0' || s[i-1]>'9') ){
            flag=1;
            i++;
            continue;
        }
        
        if(s[i]>='0' && s[i]<='9'){
            int tmp_num=0;
            while(i<n && s[i]>='0' && s[i]<='9'){
                tmp_num=10*tmp_num+s[i]-'0';
                i++;
            }
            if(flag){
                tmp_num*=-1;
                flag=0;
            }
            numStk.push(tmp_num);
        }else if(s[i]=='+' || s[i]=='-' || s[i]=='*' || s[i]=='/'){
            if(oprStk.empty()){
                oprStk.push(s[i]);
            }else{
                while(!oprStk.empty()){
                    tmp_opr=oprStk.top();
                    if(getPriority(tmp_opr)>=getPriority(s[i])){
                        //calculate
                        calculate(numStk,tmp_opr);
                        oprStk.pop();
                    }else{
                        break;
                    }
                }
                oprStk.push(s[i]);
            }
            i++;
        }else{ //s[i]=='(' || s[i]==')'
            if(s[i]=='('){
                oprStk.push(s[i]);
            }else{
                while(oprStk.top()!='('){
                    tmp_opr=oprStk.top();
                    calculate(numStk,tmp_opr);
                    oprStk.pop();
                }
                oprStk.pop();
            }
            i++;
        }
    }
    while(!oprStk.empty()){
        tmp_opr=oprStk.top();
        calculate(numStk,tmp_opr);
        oprStk.pop();
    }
    cout<<numStk.top()<<endl;
    return 0;
}

   

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值