简单四则运算 | 豆包MarsCode AI刷题

63 阅读2分钟

问题描述

小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

Solution

直接下手这个问题显然是很困难的,但是我们知道如果将表达式变成后缀表达式的话,那么使用栈就可以很轻松的解决这个问题了,那么我们知道后缀表达式怎么运算,只需要将这个表达式转换成后缀表达式就可以了。

转换成后缀表达式:

  • 遇到左括号时,将其压入栈中
  • 遇到右括号时,开始弹出栈中的运算符,并将其添加到结果列表中,直到遇到左括号
  • 对于加号和减号,只在栈顶不是左括号时才将其压入栈中
  • 对于乘号和除号,只在栈顶是左括号或者栈为空时才将其压入栈中

这样,就可以保证乘除运算的优先级高于加减运算

后面的话,就是正常的计算后缀表达式的过程了,每次取出两个数和一个运算符进行计算即可

Java代码实现
 import java.util.*;
 ​
 public class Main {
     public static int solution(String expression) {
         List<String> ex = get(expression);
         Stack<Integer> stk = new Stack<>();
         
         for (String s : ex) {
             if (Character.isDigit(s.charAt(0))) {
                 int num = Integer.parseInt(s);
                 stk.push(num);
             } else {
                 int b = stk.pop();
                 int a = stk.pop();
                 switch (s) {
                     case "+":
                         stk.push(a + b);
                         break;
                     case "-":
                         stk.push(a - b);
                         break;
                     case "*":
                         stk.push(a * b);
                         break;
                     case "/":
                         stk.push(a / b);
                         break;
                 }
             }
         }
         return stk.peek();
     }
 ​
     private static List<String> get(String s) {
         Stack<Character> stk = new Stack<>();
         List<String> ans = new ArrayList<>();
         
         for (int i = 0; i < s.length(); i++) {
             char ch = s.charAt(i);
             if (Character.isDigit(ch)) {
                 StringBuilder tmp = new StringBuilder();
                 while (i < s.length() && Character.isDigit(s.charAt(i))) {
                     tmp.append(s.charAt(i));
                     i++;
                 }
                 ans.add(tmp.toString());
                 i--;
             } else if (ch == '(') {
                 stk.push(ch);
             } else if (ch == ')') {
                 while (!stk.isEmpty() && stk.peek() != '(') {
                     ans.add(String.valueOf(stk.pop()));
                 }
                 stk.pop();
             } else if (ch == '+' || ch == '-') {
                 while (!stk.isEmpty() && stk.peek() != '(') {
                     ans.add(String.valueOf(stk.pop()));
                 }
                 stk.push(ch);
             } else if (ch == '*' || ch == '/') {
                 while (!stk.isEmpty() && stk.peek() != '(' && stk.peek() != '+' && stk.peek() != '-') {
                     ans.add(String.valueOf(stk.pop()));
                 }
                 stk.push(ch);
             }
         }
         
         while (!stk.isEmpty()) {
             char c = stk.pop();
             if (c != '(') {
                 ans.add(String.valueOf(c));
             }
         }
         return ans;
     }
 ​
     public static void main(String[] args) {
         // You can add more test cases here
         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);
     }
 }
 ​
时空复杂度

时间复杂度: O(n)

空间复杂度: O(n)

总结与思考

这是一个比较常用的问题,算法方面也比较简单,只是栈的简单应用,但是代码方面会比较多,比较锻炼代码能力