LeetCode 227. 基本计算器 II c++/java详细题解

Posted 林深时不见鹿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 227. 基本计算器 II c++/java详细题解相关的知识,希望对你有一定的参考价值。

1、题目

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

示例 1:

输入:s = "3+2*2"
输出:7

示例 2:

输入:s = " 3/2 "
输出:1

示例 3:

输入:s = " 3+5 / 2 "
输出:5

提示:

  • 1 <= s.length <= 3 * 105
  • s 由整数和算符 ('+', '-', '*', '/') 组成,中间由一些空格隔开
  • s 表示一个 有效表达式
  • 表达式中的所有整数都是非负整数,且在范围 [0, 2^31 - 1]
  • 题目数据保证答案是一个 32-bit 整数

2、思路

(栈,表达式求值) O ( n ) O(n) O(n)

对于表达式求值这类问题,我们维护两个栈,一个num栈用来记录数字,一个op栈用来记录操作符,遍历表达式,遇到操作符时进行数的相应计算。

首先我们定义一个eval()函数,用于从数字栈num中弹出两个数字ab,再从操作符栈op中弹出操作符号,进行计算后将结果数字加入到数字栈num中。

具体定义如下:

void eval() 
{
    int b = num.top(); num.pop();
    int a = num.top(); num.pop();
    char c = op.top(); op.pop();
    int r;
    if (c == '+') r = a + b;
    else if (c == '-') r = a - b;
    else if (c == '*') r = a * b;
    else r = a / b;
    num.push(r);
}

然后我们从前往后扫描整个表达式:

  • 1、当遇到空格' '时,跳过。

  • 2、当遇到数字时,则读取一个连续的完整数字,再将其加入到数字栈num中。

  • 3、当遇到'+''-''*''/' 运算符时,需要考虑优先级:

    • 如果操作符栈op的栈顶元素的优先级比当前遇到的操作符优先级高,则while循环进行eval()操作,即将数字栈num栈顶的两个元素取出来,然后和操作符栈op的栈顶操作符进行相应计算,并将计算结果压回数字栈num中。
    • 否则,将当前运算符压入操作符栈op中。
  • 4、扫描完整个表达式后,如果操作符栈op中还存在元素,则while循环进行eval()操作。

  • 5、最终返回数字栈num的栈顶元素值。

图示过程:

细节处理:

  • 1、由于运算符有优先级,所以设计一个哈希表来存储'+''-''*''/' 优先级,我们将'+''-'设为1级优先级,将'*''/'设为2级优先级。
  • 2、考虑到表达式s的第一个数字可能为负数,因此我们给s开头添加一个字符0

时间复杂度分析: 每个数字和操作进栈出栈一次,所以总的时间复杂度是 O ( n ) O(n) O(n)

3、c++代码

class Solution {
public:
    stack<int> num;  //存贮数字
    stack<char> op;  //存贮操作

    void eval() 
    {
        int b = num.top(); num.pop();
        int a = num.top(); num.pop();
        char c = op.top(); op.pop();
        int r;
        if (c == '+') r = a + b;
        else if (c == '-') r = a - b;
        else if (c == '*') r = a * b;
        else r = a / b;
        num.push(r);
    }

    int calculate(string s) {
        s = '0' + s;  // 对开头是负数的处理 
        unordered_map<char, int> pr; 
        pr['+'] = pr['-'] = 1, pr['*'] = pr['/'] = 2; //定义运算符的优先级
        for(int i = 0; i < s.size(); i++)
        {
            char c = s[i]; 
            if(c == ' ') continue;  //跳过空格
            if(isdigit(c))     //c是数字,读取一个连续的数字
            {
                int x = 0, j = i;
                while(j < s.size() && isdigit(s[j])) x = x * 10 + (s[j++] - '0');
                num.push(x);    //加入数字栈中
                i = j - 1;        
            }
            else  //c是操作符 
            {     //op栈非空并且栈顶操作符优先级大于等于当前操作符c的优先级,进行eval()计算
                while(op.size() && pr[op.top()] >= pr[c]) eval(); 
                op.push(c);
            }
        }
        while(op.size()) eval(); 
        return num.top();
    }
};

4、java代码

class Solution {
    static Stack<Integer> num = new Stack<Integer>();
    static Stack<Character> op = new Stack<Character>();
    static HashMap<Character, Integer> map = new HashMap<Character, Integer>();
    static void eval()
    {
        int b = num.pop();
        int a = num.pop();
        char c = op.pop();
        int r = 0;
        if(c == '+') r = a + b;
        else if(c == '-') r = a - b;
        else if(c == '*') r = a * b;
        else r = a / b;
        num.add(r); 
    }
    public int calculate(String s) {
        s = '0' + s; // 对开头是负数的处理 
        map.put('+', 1);   //定义运算符的优先级
        map.put('-', 1);
        map.put('*', 2);
        map.put('/', 2);
        for(int i = 0; i < s.length();i ++)
        {
            char c = s.charAt(i);
            if(c == ' ') continue;  //跳过空格
            if(c >= '0' && c <= '9')  //c是数字,读取一个连续的数字
            {
                int x = 0, j = i;
                while(j < s.length() && s.charAt(j) >= '0' && s.charAt(j) <= '9')
                {
                    x = x * 10 + s.charAt(j) - '0';
                    j ++;
                }
                i = j - 1;
                num.add(x);
            }
            else  //c是操作符 
            {     //op栈非空并且栈顶操作符优先级大于等于当前操作符c的优先级,进行eval()计算
                while(!op.isEmpty() && map.get(op.peek()) >= map.get(c)) eval();
                op.add(c); 
            }
        }
        while(!op.isEmpty()) eval();
        return num.pop();
    }
}

原题链接: 227. 基本计算器 II

以上是关于LeetCode 227. 基本计算器 II c++/java详细题解的主要内容,如果未能解决你的问题,请参考以下文章

leetcode227基本计算器II (Medium)

LeetCode 227. 基本计算器 II

Leetcode 227.基本计算器II

LeetCode227:基本计算器II

LeetCode 227. 基本计算器 II

227. 基本计算器 II