题解 | #四则运算# 字符串运算式转换为逆波兰表达式

四则运算

http://www.nowcoder.com/practice/9999764a61484d819056f807d2a91f1e

整个题解分为2部分,第一部分是根据输入的字符串表达式,构建出逆波兰表达式;第二步是根据给出的逆波兰表达式求具体值。

第一部分是难点,需要考虑到负号与负数的影响,当负号之前为括号或者没有任何符号时,不能直接入栈减号(通过开头补 0 消除),也要考虑到自然数存在大于个位数的情况,比如 100 放入栈中不是 1,0,0 这三个数。设立一个字符串 vector 存储逆波兰表达式结果,数字直接 push_back,遇到运算符先放入临时的 stack 中,后续再放入 vector 中汇总。

当第一部分构建完毕后,根据得到的逆波兰表达式数组很容易求出最终的结果,也是通过栈来实现。

代码如下,相关注释已经写全。

#include <iostream>
#include <string>
#include <stack>
#include <vector>

using namespace std;

int main() {
    string s;
    int res;
    while (getline(cin, s)) {
        vector<string> v;
        stack<char> st;
        stack<int> st1;
        // 第一部分:构建出逆波兰表达式数组 v
        // 构建原则:遇到括号与乘除无条件入栈,遇到加减把栈顶的乘除加减都弹出后再入栈(遵循运算顺序)
        // 注意减号,当其前面为括号或者是无符号(i = 0)时,需要补充一个 0,不然需要当作负数处理,入栈时该数需添加负号
        for (int i = 0; i < s.size(); i++) {
            // 遇到括号与乘除无条件入栈
            if (s[i] == '(' || s[i] == '[' || s[i] == '{' || s[i] == '*' || s[i] == '/') st.push(s[i]);
            else if (s[i] == '+' || s[i] == '-') {
                // 减号前面为括号或者是无符号(i = 0)时,需要补充一个 0
                if ((i == 0 || s[i - 1] == '(' || s[i - 1] == '[' || s[i - 1] == '{') && s[i] == '-') {
                    v.push_back("0");
                    st.push(s[i]);
                }
                else {
                    // 遇到加减把栈顶的乘除加减都弹出后再入栈(遵循运算顺序)
                    while (!st.empty() && (st.top() == '*' || st.top() == '/' || st.top() == '+' || st.top() == '-')) {
                        if (st.top() == '*') v.push_back("*");
                        else if (st.top() == '/') v.push_back("/");
                        else if (st.top() == '+') v.push_back("+");
                        else v.push_back("-");
                        st.pop();
                    }
                    st.push(s[i]);
                }
            }
            // 遇到右括号就一直弹出栈顶元素直至栈顶元素为左括号
            else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
                while (st.top() != '(' && st.top() != '[' && st.top() != '{') {
                    if (st.top() == '+') v.push_back("+");
                    else if (st.top() == '-') v.push_back("-");
                    else if (st.top() == '*') v.push_back("*");
                    else v.push_back("/");
                    st.pop();
                }
                // 弹出栈顶的左括号
                st.pop();
            }
            // 这里需要考虑自然数大于个位数的情况,比如 100 不能视作 3 个数而应该是单个数
            else {
                string tmp;
                // 0-9 的 ASCII 码为 48-57
                while (i < s.size() - 1 && s[i + 1] >= 48 && s[i + 1] <= 57) tmp += s[i++];
                // 这里 i + 1不满足时退出循环还需要再加当前的 i 因为当前的 i 是满足的
                tmp += s[i];
                v.push_back(tmp);
            }
        }
        // 最后依次弹出栈内所有元素
        while (!st.empty()) {
            if (st.top() == '+') v.push_back("+");
            else if (st.top() == '-') v.push_back("-");
            else if (st.top() == '*') v.push_back("*");
            else v.push_back("/");
            st.pop();
        }
        // 第二部分:逆波兰表达式求值
        // 依次序读取 vector 中的逆波兰表达式各个项,数字就入栈,字符就弹出 2 个执行操作后入栈
        for (int i = 0; i < v.size(); i++) {
            if (v[i] == "+" || v[i] == "-" || v[i] == "*" || v[i] == "/") {
                int tmp3;
                int tmp1 = st1.top();
                st1.pop();
                int tmp2 = st1.top();
                st1.pop();
                if (v[i] == "+") tmp3 = tmp2 + tmp1;
                else if (v[i] == "-") tmp3 = tmp2 - tmp1;
                else if (v[i] == "*") tmp3 = tmp2 * tmp1;
                else tmp3 = tmp2 / tmp1;
                st1.push(tmp3);
            }
            else st1.push(stoi(v[i]));
        }
        // 最后栈顶的元素即为最终值
        res = st1.top();
        st1.pop();
        cout << res << endl;
    }
    return 0;
}
全部评论

相关推荐

Hello_WordN:咱就是说,除了生命其他都是小事,希望面试官平安,希望各位平时也多注意安全
点赞 评论 收藏
分享
11-15 17:19
湖南大学 Java
成果成果成果果:这是哪个公司的hr,这么离谱吗,我没见过用性别卡技术岗的,身边女性同学拿大厂offer的比比皆是
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务