[leetcode] 基本计算器

本文题目:

题目 772 需要 Plus 会员,可以看这里的博客

版本 1 :只考虑个位数

实现需求

  • 有空格
  • 数字只考虑个位数
  • 无括号
  • 支持四则运算

实现思路

数据结构课上学过的栈算法,将数字与操作符分离入栈,同时利用一个 map 来记录操作符的优先级。只有当前操作符 x 优先级严格大于栈顶操作符优先级,才能进栈,否则需要先执行栈顶操作符。

代码实现

#define isDigital(x) (('0' <= (x)) && ((x) <= '9'))
#define isSign(x) (((x) == '+') || ((x) == '-') || ((x) == '*') || ((x) == '/'))
class Solution
{
public:
    unordered_map<char, int> cmp = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
    int calculate(string s)
    {
        stack<int> numbers;
        stack<char> signs;
        for (char x : s)
        {
            if (isDigital(x))  numbers.push(x - '0');
            else if (isSign(x))
            {
                while (!signs.empty() && cmp[x] <= cmp[signs.top()])
                    exec(numbers, signs);
                signs.push(x);
            }
        }
        while (!signs.empty())  exec(numbers, signs);
        assert(numbers.size() == 1);
        return numbers.top();
    }
    // exec 函数表示对栈顶操作符运算,该函数不会变
    void exec(stack<int> &nums, stack<char> &signs)
    {
        int a, b, val;
        char op;
        op = signs.top(), signs.pop();
        b = nums.top(), nums.pop();
        a = nums.top(), nums.pop();
        switch (op)
        {
            case '+': val = a + b; break;
            case '-': val = a - b; break;
            case '*': val = a * b; break;
            case '/': val = a / b; break;
            default: assert(0);
        }
        nums.push(val);
    }
};

版本 2 :考虑任意位数字

实现需求

  • 有空格
  • 数字任意多位
  • 无括号
  • 支持四则运算

实现思路

遇见数字,继续往前扫描,直到遇到非数字,这一整个子串转换为一个 int .

代码实现

这样就能通过题目 227 啦~

int calculate(string s)
{
    stack<int> numbers;
    stack<char> signs;
    int len = s.length();
    for (int i = 0; i < len; i++)
    {
        char x = s[i];
        if (isDigital(x))
        {
            int j = i;
            while (isDigital(s[j]))  j++;
            numbers.push(stoi(s.substr(i, j - i)));
            i = j - 1;
        }
        else if (isSign(x))
        {
            while (!signs.empty() && cmp[x] <= cmp[signs.top()])
                exec(numbers, signs);
            signs.push(x);
        }
    }
    while (!signs.empty())  exec(numbers, signs);
    assert(numbers.size() == 1);
    return numbers.top();
}

版本 3 :考虑括号

实现需求

  • 有空格
  • 数字任意多位
  • 带括号
  • 支持四则运算
  • 考虑负数

实现思路

很明显,对于带括号的表达式 1+2*(1+2*(3)) ,括号中是一个子表达式,同样要进行求值处理,显示需要采用递归做法。

那么现在需要解决的就是:当遇到 '(' 时,找到该 '(' 包围的子表达式。需要使用括号匹配算法。

代码实现

可以通过 224 ,估计 772 也行。

int calculate(string s)
{
    stack<int> numbers;
    stack<char> signs;
    int len = s.length();
    // 考虑负数, e.g. "-111-(-222*2)"
    if (len > 0 && s[0] == '-') numbers.push(0);
    for (int i = 0; i < len; i++)
    {
        char x = s[i];
        if (isDigital(x))
        {
            int j = i;
            while (isDigital(s[j]))  j++;
            numbers.push(stoi(s.substr(i, j - i)));
            i = j - 1;
        }
        else if (isSign(x))
        {
            while (!signs.empty() && cmp[x] <= cmp[signs.top()])
                exec(numbers, signs);
            signs.push(x);
        }
        else if (x == '(')
        {
            int flag = 0;
            int j = i;
            do
            {
                if (s[j] == '(')  flag++;
                else if (s[j] == ')')  flag--;
                j++;
            } while (flag != 0);
            numbers.push(calculate(s.substr(i + 1, j - 1 - i - 1)));
            i = j - 1;
        }
    }
    while (!signs.empty())  exec(numbers, signs);
    assert(numbers.size() == 1);
    return numbers.top();
}
posted @ 2020-09-12 20:37  sinkinben  阅读(530)  评论(1编辑  收藏  举报