表达式求值

64 阅读2分钟

image.png

点击跳转

方法一:栈(迭代)——思路与代码要点

核心想法:用两个栈——nums 存放数字、ops 存放运算符。遍历字符串:

  • 遇到数字,解析完整的多位整数并入 nums
  • 遇到 (,直接入 ops
  • 遇到 ),一直弹出 ops 并对 nums 做计算,直到遇到对应的 (
  • 遇到运算符(+ - *),在入栈之前先把 ops 栈顶上优先级 >= 当前运算符的那些都执行掉(注意 ( 是阻断符),然后再把当前运算符入栈。
  • 遍历结束后把剩余运算都执行完。

这利用算术优先级(* 高于 +/-)和括号优先规则保证正确顺序。

#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    int solve(string s) {
        return calculate_stack(s);
    }

private:
    int applyOp(int a, int b, char op) {
        if (op == '+') return a + b;
        if (op == '-') return a - b;
        if (op == '*') return a * b;
        return 0;
    }

    int calculate_stack(const string &s) {
        stack<int> nums;
        stack<char> ops;
        unordered_map<char, int> prec = {{'+',1},{'-',1},{'*',2}};
        int n = s.size();
        for (int i = 0; i < n; ) {
            char ch = s[i];
            if (ch == ' ') {
                i++;
                continue;
            }
            if (isdigit(ch)) {
                int num = 0;
                while (i < n && isdigit(s[i])) {
                    num = num * 10 + (s[i]-'0');
                    i++;
                }
                nums.push(num);
                continue;
            }
            if (ch == '(') {
                ops.push(ch);
            } else if (ch == ')') {
                while (!ops.empty() && ops.top() != '(') {
                    int b = nums.top(); nums.pop();
                    int a = nums.top(); nums.pop();
                    nums.push(applyOp(a,b,ops.top()));
                    ops.pop();
                }
                if (!ops.empty()) ops.pop(); // 弹出'('
            } else { // 运算符
                while (!ops.empty() && ops.top() != '(' && prec[ops.top()] >= prec[ch]) {
                    int b = nums.top(); nums.pop();
                    int a = nums.top(); nums.pop();
                    nums.push(applyOp(a,b,ops.top()));
                    ops.pop();
                }
                ops.push(ch);
            }
            i++;
        }
        while (!ops.empty()) {
            int b = nums.top(); nums.pop();
            int a = nums.top(); nums.pop();
            nums.push(applyOp(a,b,ops.top()));
            ops.pop();
        }
        return nums.top();
    }
};

方法二:递归(分治 + 当前层栈)——思路与代码要点

核心想法:用递归来处理括号。写一个 helper(i),从位置 i 开始解析“当前层”到遇到 )(或字符串结尾)为止,返回该层的计算结果与解析停下的位置索引。当前层内部按同样的规则处理运算优先级:用一个局部 vector<int> stk 存放所有加/减项,但在遇到 * 时直接与栈顶合并(实现乘法优先)。

#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    int solve(string s) {
        int idx = 0;
        return helper(s, idx);
    }

private:
    int helper(const string &s, int &i) {
        vector<int> stk;
        int num = 0;
        char sign = '+';
        while (i < (int)s.size()) {
            char ch = s[i];
            if (isdigit(ch)) {
                num = num * 10 + (ch - '0');
            }
            if (ch == '(') {
                i++;
                num = helper(s, i);
            }
            if ((!isdigit(ch) && ch != ' ') || i == (int)s.size()-1) {
                if (sign == '+') stk.push_back(num);
                else if (sign == '-') stk.push_back(-num);
                else if (sign == '*') stk.back() *= num;
                sign = ch;
                num = 0;
            }
            if (ch == ')') {
                return accumulate(stk.begin(), stk.end(), 0);
            }
            i++;
        }
        return accumulate(stk.begin(), stk.end(), 0);
    }
};