[LeetCode]Basic Calculator II

本文介绍了一种通过转换算术表达式为逆波兰表达式来简化计算器的设计方法。包括去除空格、分离运算符与操作数、转换为逆波兰表达式及计算结果的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解题思路:
1,就是要写个简单的计算器呗
2,先把所有的 space去掉, 实现nonSpace方法;
3,把所有的 operator 和 operands分开,实现简单的 splitToOper 方法;
4,第3步得到的序列,是算数表达式的中缀表达式,计算机不好懂,要转换成逆波兰表达式;实现RPExpression方法
5,有了上述输入序列,这个题就变的跟  Evaluate Reverse Polish Notation 一样简单了
6,除了上述方法,我还写了getPriority, isOperator, strintToInt, doCalculate等辅助方法

下面简述逆波兰表达式的逻辑:
1,前条件:tokens,输入序列
                   queue<string> s1, 用于存放结果;          
                    stack<string> sOper, 用于存放操作符
                    sOper.push(‘#’),方便写程序, ‘#’优先级最低
2,不变式:遍历tokens中的每一个字符串elem
          a,如果elem是数字,直接加入s.push
          b,如果elem是操作符,计算优先级newp;取sOper.top,计算优先级p,
                 i, 如果newp > p, 则sOper.push(elem);break;
                ii,否则,s1.push(sOper.top),sOper.pop。再执行b后半部分,直到出现 i 这个情况
3,结束条件:tokens遍历完,把sOper剩余的elem出了’#’都push到s1
     把s1放到vector里面,返回

边界条件:自从push了’#’,就避开了 


class Solution {
public:
    enum Priority{
        BEFORE = 0,
        LOW,
        HIGH
    };
    int calculate(string s) {
        // delete space
        nonSpace(s);

        // splite to operators and operands
        vector<string> opers;
        splitToOper(s, opers);
        printf("size of opers %d\n", (int)opers.size());

        // convert to RPExpression
        vector<string> RPN = RPExpression(opers);
        printf("size of RPN %d\n", (int)RPN.size());
        // 
        // stacks
        stack<int> operands;
        for (auto elem: RPN){
            char ch = elem[elem.length() - 1];
            if (isOperator(ch)){
                doCalculate(ch, operands);
            }else{
                operands.push(stringToInt(elem));
            }
        }
        printf("size of operands %d\n", (int)operands.size());
        return operands.top();
    }

    vector<string> RPExpression(vector<string> &opers){
        queue<string> s1;
        stack<string> sOper;
        sOper.push(string("#"));

        for (auto elem: opers){
            char ch = elem[elem.length() - 1];
            if (isOperator(ch)){
                Priority newp = getPriority(ch);

                while(!sOper.empty()){
                    string op = sOper.top();
                    Priority lastp = getPriority(op.at(0));

                    if (newp > lastp){
                        sOper.push(elem);
                        break;
                    }else{
                        s1.push(op);
                        sOper.pop();
                    }
                }
            }else{
                s1.push(elem);
            }
        }

        while(!sOper.empty()){
            string op = sOper.top();
            sOper.pop();
            if (op != "#"){
                s1.push(op);
            }
        }
        vector<string > ret;
        while(!s1.empty()){
            ret.push_back(s1.front());
            s1.pop();
        }
        return ret;
    }

    void doCalculate(char oper, stack<int> &operands){
        int next = operands.top();
        operands.pop();
        int pre = operands.top();
        operands.pop();
        int ret;
        switch(oper){
        case '*':
            ret = pre * next;
            break;
        case '/':
            ret = pre / next;
            break;
        case '+':
            ret = pre + next;
            break;
        case '-':
            ret = pre - next;
            break;
        default:
            break;
        }
        operands.push(ret);
    }

    int stringToInt(string &s){
        return atoi(s.c_str());
    }

    void splitToOper(string &str, vector<string> &tokens){
        auto wordStart = str.begin();
        auto it = str.begin();
        bool isPreWord = false;
        while(it != str.end()){
            if (!isdigit(*it)){
                if (isPreWord){
                    isPreWord = false;
                    string app(wordStart, it);
                    tokens.push_back(app);
                    tokens.push_back(string(it, it+1));
                }
            }else{
                if (!isPreWord){
                    isPreWord = true;
                    wordStart = it;
                }
            }
            it ++;
        }
        if (wordStart != it){
            tokens.push_back(string(wordStart, it));
        }
    }

    void nonSpace(string &str){
        auto it = str.begin();
        while(it != str.end()){
            if (*it == ' '){
                it = str.erase(it);
            }else{
                it++;
            }
        }
    }

    bool isOperator(char ch){
        return !isdigit(ch);
    }

    Priority getPriority(char ch){
        Priority ret;
        switch(ch){
            case '*':
            case '/':
                ret = HIGH;
                break;
            case '+':
            case '-':
                ret = LOW;
                break;
            case '#':
                ret = BEFORE;
                break;
            default:
                printf("invalid operator");
                break;
        }
        return ret;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值