一个数字栈实现Java表达式四则运算,拓展到有括号的情况

表达式求值,支持单位正整数的加、减、乘、除运算,并支持用括号表示优先级别。
表达式一定有效,且只包含正整数,结果也自动转为整数。

先看一道不包含括号的类似的题:
参考LeetCode227. Basic Calculator II
解法:
思路:
1.遍历字符串,当遇到运算符或读到末尾,判断前一个运算符
2.之前为+,入栈数字;之前为-,入栈相反数;之前为*或/,出栈数字计算后再入栈。
3.当前运算符变为前一个运算符,继续遍历。
4.遍历结束,若栈不为空,循环出栈数字求和。
代码:

class Solution {
    
        static Set<Character> set;
    
        static {
            set = new HashSet<>();
            set.add('+');
            set.add('-');
            set.add('*');
            set.add('/');
        }
    
        public static int calculate(String s) {
    
            int num = 0;
            Stack<Integer> stack = new Stack<>();
            char sign = '+';
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (Character.isDigit(c)) {
                    num = num * 10 + c - '0';
                }
                if (set.contains(c) || i == s.length() - 1) {
                    if (sign == '+') {
                        stack.push(num);
                    } else if (sign == '-') {
                        stack.push(-num);
                    } else if (sign == '*') {
                        int tmp = stack.pop() * num;
                        stack.push(tmp);
                    } else if (sign == '/') {
                        int tmp = stack.pop() / num;
                        stack.push(tmp);
                    }
                    sign = c;
                    num = 0;
                }
            }
            int result = 0;
            while (!stack.isEmpty()) {
                result += stack.pop();
            }
            return result;
        }
    
}

然后再看包含括号的情况,参考LeetCode224. Basic Calculator。一种直接简单的解法是直接在上一题的基础上修改下,如果遍历到左括号,则记录下左边界,继续遍历直到匹配的右括号,将括号里的子表达式递归求值,然后从新的起点继续遍历。(代码1)
当然,我们很容易发现代码1重复遍历了括号中的子串,当然,我们也可以一次遍历就算出表达式结果。我们使用一个全局变量i标记当前遍历的索引值,当遇到左括号开始递归遍历,遇到右括号返回当前递归的子表达式的值,递归返回后,我们立即处理这个值入栈而不是等到下一个运算符出现,因为可能没有下一个运算符了,要考虑到右括号是最后一个字符这种情况。(见代码2)
代码1:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

public class Eval
{

    private static int eval(String s)
    {
        Stack<Integer> st = new Stack<>();
        //sign表示之前的运算符
        char sign = '+';
        String operator = "+-*/";
        int num = 0;
        for(int i = 0;i<s.length();i++){
            char c = s.charAt(i);
            if(Character.isDigit(c)){
                num = num * 10 + c - '0';
            }
            if(operator.indexOf(c) != -1 ||  i == s.length()-1){
                if(sign == '+')
                {
                    st.push(num);
                }
                else if(sign == '-')
                {
                    st.push(-num);
                }
                else if(sign == '*')
                {
                    st.push(st.pop() * num);
                }
                else if(sign == '/')
                {
                    st.push(st.pop() / num);
                }
                sign = c;
                num = 0;
            }
            if(c == '('){
                int cnt = 1;
                int j = i;
                while(cnt != 0){
                    j++;
                    if(s.charAt(j) == '(') cnt++;
                    else if(s.charAt(j) == ')') cnt--;
                }
                String sub = s.substring(i+1,j);
                num = eval(sub);
                i = j-1;
            }
        }
        int res = 0;
        while(!st.isEmpty()){
            res += st.pop();
        }
        return res;
    }


    public static void main(String[] args) throws IOException
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String exp;
        while((exp = br.readLine()) != null)
        {
            int ans = eval(exp);
            System.out.println(exp + " = " + ans);
        }
    }
}

代码2:

class Solution {
	static int i=0;
	public static int calculate(String s) {
	    Stack<Integer> st = new Stack();
	    //sign表示之前的运算符
	    char sign = '+';
	    String operator = "+-*/";
	    int num = 0;
	    int len = s.length();
	    for(;i<len;i++){
	        char c = s.charAt(i);
	        if(Character.isDigit(c)){
	            num = num * 10 + c - '0';
	        }
	        if(operator.indexOf(c) != -1 ||  i == s.length()-1 ||  s.charAt(i+1) == ')'){
	            pushOperand(st, sign, num);
	            sign = c;
	            num = 0;
	        }
	        if(c == '('){
	            i=i+1;
	            num = calculate(s);
	            //下面的代码考虑的是,右括号作为结束的情况
	            pushOperand(st, sign, num);
	            sign = c;//只要不是运算符就不会重复
	            num = 0;
	        }
	        if(c == ')'){
	            return getResult(st);
	        }
	
	    }
	    return getResult(st);
	}
	
	private static int getResult(Stack<Integer> st) {
	    int res = 0;
	    while (!st.isEmpty()) {
	        res += st.pop();
	    }
	    return res;
	}
	
	private static void pushOperand(Stack<Integer> st, char sign, int num) {
	    if (sign == '+') {
	        st.push(num);
	    } else if (sign == '-') {
	        st.push(-num);
	    }else if(sign == '*'){
	        st.push(st.pop() * num);
	    }else if(sign == '/'){
	        st.push(st.pop() / num);
	    }
	}
	public static void main(String[] args) throws IOException
	 {
	     BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	     String exp;
	     while((exp = br.readLine()) != null)
	     {
	         int ans = eval(exp);
	         System.out.println(exp + " = " + ans);
	     }
	 }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wsws100

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值