简单四则运算解析器(算法解析)| 豆包MarsCode AI刷题

140 阅读4分钟

简单四则运算解析器

问题描述

小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+-及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval函数。


测试样例

样例1:

输入:expression = "1+1"
输出:2

样例2:

输入:expression = "3+4*5/(3+2)"
输出:7

样例3:

输入:expression = "4+2*5-2/1"
输出:12

样例4:

输入:expression = "(1+(4+5+2)-3)+(6+8)"
输出:23

样例5:

输入:expression = "2*(5+5*2)/3+(6+8*3)"
输出:40

问题理解

题目要求实现一个简单的四则运算解析器,能够计算包含数字、加减乘除运算符以及括号的字符串表达式的值。表达式中不包含空格,并且除法运算只保留整数结果。

数据结构选择

为了处理这种表达式,我们可以使用两个栈:

  1. 数字栈:用于存储表达式中的数字。
  2. 操作符栈:用于存储表达式中的操作符。

算法步骤

  1. 遍历表达式:从左到右遍历表达式的每个字符。

  2. 处理数字:如果当前字符是数字,将其转换为整数并压入数字栈。

  3. 处理左括号:如果当前字符是左括号(,将其压入操作符栈。

  4. 处理右括号:如果当前字符是右括号),则从操作符栈中弹出操作符,并从数字栈中弹出两个数字进行计算,直到遇到左括号(

  5. 处理操作符:如果当前字符是操作符(+-*/),则根据操作符的优先级进行处理:

    • 如果操作符栈顶的操作符优先级高于或等于当前操作符,则先进行栈顶操作符的计算。
    • 否则,将当前操作符压入操作符栈。
  6. 处理剩余操作符:遍历结束后,如果操作符栈中还有操作符,依次弹出并进行计算。

  7. 返回结果:最终数字栈中的唯一元素即为表达式的计算结果。

代码如下:

import java.util.*;
public class Main {
    public static int solution(String expression) {
        // 首先创建两个栈,一个用于存储数字,一个用于存储操作符
        Stack<Integer> numStack = new Stack<>();
        Stack<Character> opStack = new Stack<>();

        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (Character.isDigit(c)) {
                int num = c - '0';
                numStack.push(num);
            }
            else if (c == '(') {
                opStack.push(c);
            }
            else if (c == ')') {
                while (!opStack.isEmpty() &&opStack.peek()!= '(') {
                    char op = opStack.pop();
                    int b = numStack.pop();
                    int a = numStack.pop();
                    numStack.push(calculate(a, b, op));
                }
                opStack.pop();
            }
            // 如果是操作符
            else if (c == '+' || c == '-' || c == '*' || c == '/') {
                while (!opStack.isEmpty() && opStack.peek() != '(' && precedence(c) <= precedence(opStack.peek())) {
                    char op = opStack.pop();
                    int b = numStack.pop();
                    int a = numStack.pop();
                    numStack.push(calculate(a, b, op));
                }
                opStack.push(c);
            }
        }

        // 处理剩余的操作符
        while (!opStack.isEmpty()) {
            char op = opStack.pop();
            int b = numStack.pop();
            int a = numStack.pop();
            numStack.push(calculate(a, b, op));
        }
        // 返回最终结果
        return numStack.pop();
    }

    // 定义操作符的优先级
    public static int precedence(char op) {
        if (op == '+' || op == '-') {
            return 1;
        } else if (op == '*' || op == '/') {
            return 2;
        }
        return 0;
    }
    public static int calculate(int a, int b, char op) {
        switch (op) {
            case '+':
                return a + b;
            case '-':
                return a - b;
            case '*':
                return a * b;
            case '/':
                return a / b;
            default:
                throw new IllegalArgumentException("Invalid operator: " + op);
        }
    }

    public static void main(String[] args) {
        System.out.println(solution("1+1") == 2);
        System.out.println(solution("3+4*5/(3+2)") == 7);
        System.out.println(solution("4+2*5-2/1") == 12);
        System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);
    }
}

知识点总结:

1. 栈(Stack)

栈是一种后进先出(LIFO)的数据结构,非常适合用于解析和计算表达式。在这个问题中,我们使用两个栈:

  • 数字栈:用于存储表达式中的数字。
  • 操作符栈:用于存储表达式中的操作符。

2. 操作符优先级

在处理表达式时,操作符的优先级非常重要。我们需要根据操作符的优先级来决定何时进行计算。常见的优先级如下:

  • * 和 / 的优先级高于 + 和 -
  • 括号 () 可以改变运算顺序,需要优先处理。

3. 表达式解析

解析表达式时,我们需要从左到右遍历每个字符,并根据字符的类型进行不同的处理:

  • 数字:将其转换为整数并压入数字栈。
  • 左括号 (:将其压入操作符栈。
  • 右括号 ):从操作符栈中弹出操作符,并从数字栈中弹出两个数字进行计算,直到遇到左括号 (
  • 操作符:根据操作符的优先级进行处理,如果当前操作符的优先级低于或等于栈顶操作符的优先级,则先进行栈顶操作符的计算。

通过上述知识点和代码示例,我们可以实现一个简单的四则运算解析器。